【问题标题】:Recursion: Longest Palindrome Substring递归:最长回文子串
【发布时间】:2021-05-15 21:44:12
【问题描述】:

这是一个非常常见的问题,我们必须找到最长的子字符串,它也是给定输入字符串的回文子字符串。

现在有多种可能的方法,我知道动态编程解决方案,从中间扩展等。所有这些解决方案都应该用于任何实际用例。

我正在尝试使用递归来解决这个问题并尝试实现这个简单的想法。

让我们假设s 是给定的输入字符串,ij 表示输入字符串的任何有效字符索引。所以如果s[i] == s[j],我最长的子串是:

s.charAt(i) + longestSubstring(s, i + 1, j - 1) + s.charAt(j)

如果这两个字符不相等则:

max of longestSubstring(s, i + 1, j) or longestSubstring(s, i, j - 1)

我尝试在下面实施此解决方案:

// end is inclusive
private static String longestPalindromeHelper(String s, int start, int end) {
    if (start > end) {
        return "";
    } else if (start == end) {
        return s.substring(start, end + 1);
    }
    // if the character at start is equal to end
    if (s.charAt(start) == s.charAt(end)) {
        // I can concatenate the start and end characters to my result string
        // plus I can concatenate the longest palindrome in start + 1 to end - 1
        // now logically this makes sense to me, but this would fail in the case
        // for ex: a a c a b d k a c a a (space added for visualization)
        // when start = 3 (a character)
        // end = 7 (again end character)
        // it will go in recursion with start = 4 and end = 6 from now onwards
        // there is no palindrome substrings apart from the single character
        // substring (which are palindrome by itself) so recursion tree for
        // start = 3 and end = 7 would return any single character from b d k
        // let's say it returns b so result would be a a c a b a c a a
        // this would be correct answer for longest palindrome subsequence but
        // not substring because for sub strings I need to have consecutive
        // characters
        return s.charAt(start)
                + longestPalindromeHelper(s, start + 1, end - 1) + s.charAt(end);
    } else {
        // characters are not equal, increment start
        String s1 = longestPalindromeHelper(s, start + 1, end);
        String s2 = longestPalindromeHelper(s, start, end - 1);
        return s1.length() > s2.length() ? s1 : s2;
    }
}
public static String longestPalindrome(String s) {
    return longestPalindromeHelper(s, 0, s.length() - 1);
}
public static void main(String[] args) throws Exception {
    String ans = longestPalindrome("aacabdkacaa");
    System.out.println("Answer => " + ans);
}

暂时让我们忘记时间复杂度或运行时间。我专注于使其适用于上述简单案例。 正如您在 cmets 中看到的那样,我知道为什么这会失败,但我努力按照完全相同的方法纠正问题。我不想在这里使用循环。

以下相同方法的可能解决方法是什么?

注意:我对作为答案的实际字符串感兴趣,而不是长度。仅供参考,我查看了所有其他问题,似乎没有人遵循这种方法来确保正确性,所以我正在尝试。

【问题讨论】:

    标签: java string recursion dynamic-programming


    【解决方案1】:

    一旦您接到s[i] == s[j] 的呼叫,您可以翻转某种标志(或切换到修改后的方法),以告知子呼叫他们不能再使用“不匹配,尝试@987654322 @ 和 j - 1" 分支(else 条件)。这可确保您在剩余的递归中查看子字符串,而不是子序列。

    其次,即使s[i] == s[j],您也应该尝试i + 1j - 1,就好像这些字符不匹配一样,因为这些字符中的一个或两个可能不是@987654328 之间的最终最佳子字符串的一部分@ 和 j。在子序列版本中,没有任何理由不向当前回文子序列添加任何匹配字符,范围为​​ij,但子字符串并非总是如此。

    例如,给定输入 "aabcbda",并且我们处于 i = 1j = length - 1 的调用框架,我们需要最大化三种可能性:

    1. 最佳子字符串同时包含'a' 字符。调用带有标志的子例程,该标志表明我们必须从两端向下消耗并且不能再尝试跳过字符。
    2. 最好的子字符串可能仍然包括s[i],但不包括s[j],试试j - 1
    3. 最好的子字符串可能仍然包括s[j],但不包括s[i],试试i + 1

    另一个观察结果:将最佳索引传递到辅助调用链上可能更有意义,然后在包装函数的最后根据这些索引获取最长的回文子字符串。

    类似地,如果您遇到困难,您可以简化问题并使用递归方法返回最长的回文子串长度,然后切换到获取实际子串本身。这样可以更轻松地专注于消除子序列逻辑。

    【讨论】:

      【解决方案2】:

      在这里使用循环比使用递归要容易得多,如下所示:

      public static void main(String[] args) {
          System.out.println(longestPalindrome("abbqa")); // bb
          System.out.println(longestPalindrome("aacabdkacaa")); // aca
          System.out.println(longestPalindrome("aacabdkaccaa")); // acca
      }
      
      public static String longestPalindrome(String str) {
          String palindrome = "";
          for (int i = 0; i < str.length(); i++) {
              for (int j = i; j < str.length(); j++) {
                  String substring = str.substring(i, j);
                  if (isPalindrome(substring)
                          && substring.length() > palindrome.length()) {
                      palindrome = substring;
                  }
              }
          }
          return palindrome;
      }
      
      public static boolean isPalindrome(String str) {
          for (int i = 0; i < str.length() / 2; i++) {
              if (str.charAt(i) != str.charAt(str.length() - i - 1)) {
                  return false;
              }
          }
          return true;
      }
      

      【讨论】:

        猜你喜欢
        • 2015-07-09
        • 2019-05-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-24
        • 1970-01-01
        • 2018-06-23
        相关资源
        最近更新 更多