Java 递归:最长回文子串

Java 递归:最长回文子串,java,string,recursion,dynamic-programming,Java,String,Recursion,Dynamic Programming,这是一个非常常见的问题,我们必须找到最长的子字符串,它也是给定输入字符串的回文子字符串 现在有多种可能的方法来解决这个问题,我知道动态规划解决方案,从中间展开等等。所有这些解决方案都应该用于任何实际用例 我正在尝试使用递归来解决这个问题,并试图实现这个简单的想法 假设s是给定的输入字符串,i和j表示输入字符串的任何有效字符索引。因此,如果s[i]==s[j],我的最长子串将是: s.charAt(i)+最长子串(s,i+1,j-1)+s.charAt(j) 如果这两个字符不相等,则: max

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

现在有多种可能的方法来解决这个问题,我知道动态规划解决方案,从中间展开等等。所有这些解决方案都应该用于任何实际用例

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

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

s.charAt(i)+最长子串(s,i+1,j-1)+s.charAt(j)
如果这两个字符不相等,则:

max of longestSubstring(s, i + 1, j) or longestSubstring(s, i, j - 1)
我尝试在下面实施此解决方案:

//结束是包含的
私有静态字符串longestPalindromeHelper(字符串s,int-start,int-end){
如果(开始>结束){
返回“”;
}else if(开始==结束){
返回s.substring(开始、结束+1);
}
//如果起始字符等于结束字符
如果(s.charAt(开始)=s.charAt(结束)){
//我可以将开始字符和结束字符连接到结果字符串
//另外,我可以将start+1中最长的回文连接到end-1
//从逻辑上讲,这对我来说是有意义的,但在这种情况下,这将失败
//例如:a c a b d k a c a(为可视化添加的空间)
//当start=3时(一个字符)
//end=7(同样是结束字符)
//从现在起,它将以start=4和end=6进行递归
//除了单个字符外,没有回文子字符串
//子字符串(本身是回文的)所以递归树
//start=3和end=7将返回来自bdk的任何单个字符
//假设它返回b,那么结果就是
//这将是最长回文子序列的正确答案,但
//不是子字符串,因为对于子字符串,我需要连续
//人物
返回s.charAt(开始)
+最长的回文助手(s,开始+1,结束-1)+s.charAt(结束);
}否则{
//字符不相等,递增开始
字符串s1=最长的回文助手(s,开始+1,结束);
字符串s2=最长的回文助手(s,开始,结束-1);
返回s1.length()>s2.length()?s1:s2;
}
}
公共静态字符串最长回文(字符串s){
返回最长的回文助手(s,0,s.length()-1);
}
publicstaticvoidmain(字符串[]args)引发异常{
字符串ans=最长回文(“aacabdkaca”);
System.out.println(“Answer=>”+ans);
}
让我们暂时忘记时间复杂性或运行时。我专注于使其适用于上述简单案例。 正如您在评论中所看到的,我知道了为什么这会失败,但我努力按照完全相同的方法纠正问题。我不想在这里使用循环

以下相同方法的可能修复方法是什么?


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

一旦您有一个调用,其中
s[I]==s[j]
,您可以翻转某种标志(或切换到修改过的方法),该标志与子调用通信,这些子调用不再使用“如果不匹配,请尝试
i-1
j-1
”分支(
else
条件)。这样可以确保在递归的其余部分中查看的是子字符串,而不是子序列。”

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

例如,给定输入
“aabcbda”
,我们处于调用帧,其中
i=1
j=length-1
,我们需要最大化三种可能性:

  • 最好的子字符串包含两个
    'a'
    字符。调用带有标志的子例程,该标志表示我们必须从两端向下消费,并且不能再尝试跳过字符
  • 最好的子字符串可能仍然包括
    s[i]
    ,但不包括
    s[j]
    ,请尝试
    j-1
  • 最好的子字符串可能仍然包括
    s[j]
    ,但不包括
    s[i]
    ,请尝试
    i+1
  • 另一个观察结果是:将最好的索引传递给helper调用链,然后在包装器函数的最末端根据这些索引获取最长的回文子串可能更有意义

    类似地,如果您正在努力,您可能会简化问题,使用递归方法返回最长的回文子字符串长度,然后切换到获取实际的子字符串本身。这样可以更容易地集中精力消除子序列逻辑。

    在这里使用循环比使用递归更容易例如:

    publicstaticvoidmain(字符串[]args){
    System.out.println(最长回文(“abbqa”);//bb
    System.out.println(最长回文(“aacabdkaca”);//aca
    System.out.println(最长回文(“aacabdkaccaa”);//acca
    }
    
    public静态字符串longestPalindrome(String str){
    字符串回文=”;
    对于(int i=0;i