当前位置: 首页 > 知识库问答 >
问题:

最长回文子串自顶向下递归方法

薛烨霖
2023-03-14

我试图解决Leetcode上最长的回文子串。我知道这个问题的解决方案,比如围绕中心展开或动态编程自下而上的方法。出于纯粹的教育目的,我想以自上而下的递归方式解决这个问题。我试图找到类似于这里或这里描述的解决方案。(问题略有不同)。我有这个功能:

private (int Start, int End) Longest(string s, int i, int j)

它接受搜索的字符串开始和结束位置。返回的元组是最长palindrom的开始和结束。我试图分成以下情况:

  1. 如果s[i]==s[j],则调查最长(s,i 1,j-1)
  2. 调查最长(s,i 1,j)
  3. 调查最长(s,i,j-1)
  4. 从这三个值返回最长值(返回的开始和结束之间的最大差值)

当然,我使用元组(int, int)作为键(i和j的值)的字典来记住所有计算结果,而不是再次计算它们。

下面是完整的代码,但当我试图修复算法时,经过几次迭代后,代码非常混乱。我认为concreate代码不是很重要。

代码似乎返回了正确的结果,但在超出Leetcode的时间限制时失败。有正确的快速递归解决方案吗?我认为应该存在DP自下而上的解决方案。

代码:

private readonly IDictionary<(int, int), (int, int)> _mem = new Dictionary<(int, int), (int, int)>();

private (int Start, int End) Longest(string s, int i, int j) {
    if (i >= j) {
        return (i, j);
    }

    if (_mem.TryGetValue((i, j), out var ret)) {
        return ret;
    }

    var newI = i + 1;
    var newJ = j - 1;

    ValueTuple<int, int> removingTwo;

    if (s[i] == s[j])
    {
        removingTwo = Longest(s, newI, newJ);

        if (removingTwo.Item1 == newI && removingTwo.Item2 == newJ) {
            removingTwo.Item1--;
            removingTwo.Item2++;
        }
    }
    else {
        removingTwo = (1, 0);
    }

    var removingFirst = Longest(s, newI, j);
    var removingLast = Longest(s, i, newJ);  

    var mT = removingTwo.Item2 - removingTwo.Item1;
    var mF = removingFirst.End - removingFirst.Start;
    var mL = removingLast.End - removingLast.Start;

    var max = Math.Max(mT, mF);
    max = Math.Max(max, mL);

    ValueTuple<int, int> retVal;

    if (max == mT) retVal = removingTwo;
    else if (max == mF) retVal = removingFirst;
    else retVal = removingLast;

    _mem.Add((i, j), retVal);

    return retVal;

}

编辑:工作自下而上的解决方案(从geegsforgeegs复制):

public string LongestPalindrome(string s) {
    if (s.Length == 0) return "";
    var table = new bool[s.Length, s.Length];
    var len = s.Length;
    for (int i = 0; i < len; i++) {
        table[i,i] = true;
    }

    var start = 0;
    var max = 1;
    for (int i = 0; i < len - 1; i++) {
        if (s[i] == s[i + 1]) {
            start = i;
            max = 2;
            table[i, i+1] = true;
        }
    }

    for (int k = 3; k <= len; ++k) { 

              // Fix the starting index 
        for (int i = 0; i < len - k + 1; ++i)  
        { 
            // Get the ending index of substring from 
            // starting index i and length k 
            int j = i + k - 1; 

            // checking for sub-string from ith index to 
            // jth index iff str.charAt(i+1) to  
            // str.charAt(j-1) is a palindrome 
            if (table[i + 1, j - 1] && s[i] == s[j]) { 
                table[i,j] = true; 

                if (k > max) { 
                    start = i; 
                    max = k; 
                } 
            } 
        } 
    } 

    return s.Substring(start, max);
}

共有2个答案

蒙奇
2023-03-14

简单的递归解决方案,不是记忆化

 def palandrom(A,i,j):
        if i > j: 
            return ''
        elif i == j: 
            return A[i]
    
        elif A[i] == A[j]: 
            save = A[i+1 : j]
            if save == save[::-1]:
                i = len(A) #As we know rest of string are palandrome we want to make i>j condition true 

                return (A[i] + save + A[j])
    
        left = palandrom(text,i+1,j)
        right = palandrom(text,j,j+1)
        return left if len(left) > len(right) else right
    
    print(palandrom(loiol,0,4))
邢焕
2023-03-14

这里是Python中通过LeetCode测试的递归方法。这可能是因为他们正在寻找一个恒定的空间解。

f(i, k)返回(l, j),长度l的最大元组及其起始索引jmax在本例中正在查看返回元组的第一个元素,即l,回文的长度。

def longestPalindrome(self, s):
  def f(i, k):
    return max(
      # next iteration
      f(i - 1, 1) if k < 2 and i > 0 else (-1,-1),
      f(i - 1, 2) if k < 2 and i > 0 and s[i-1] == s[i] else (-1, -1),

      # a larger palindrome than this one
      f(i - 1, k + 2) if i > 0 and i + k < len(s) and s[i-1] == s[i + k] else (-1, -1),

      # this one
      (k, i)
    )

  (l, j) = f(len(s) - 1, 1)
  return s[j:j+l]
 类似资料:
  • 以下是我尝试过的,但在某些情况下失败了,但我觉得我几乎走上了正确的轨道。

  • 问题-给定一个长度为N的整数数组,求最长子序列的长度,该序列先增加后减少。投入:[1,11,2,10,4,5,2,1] 产出:6 说明:[1,210,4,21]是最长的子序列。 我写了一个自上而下的方法。我有五个参数--vector A(包含序列)、start index(表示当前索引)、previer value、large(表示当前子序列中的最大值)和map(m)stl。 对于回溯方法,我有两

  • 我正试图从leet代码中解决一个问题。我为此写了一个方法。这在local Eclipse中工作得很好,但是当我在leetcode上提交这个解决方案时,它说超过了时间限制。 有人能给我一些建议吗?我可以在下面的代码中修改一些东西,以使它更快地工作?我也可以在这个帖子中输入字符串。 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

  • 我正在尝试理解递归排序函数,它是mergesort算法的一部分。下面是我的代码,我几乎可以肯定它是正确的(通过在线课程)。 我理解合并的作用——它将每个子数组分解成两个较小的子数组,重复这个过程,直到子数组的长度为1(根据定义排序),然后合并。然而,这个排序函数用来完成这个任务的实际方法对我来说很难理解。也许是因为我不习惯递归函数,但是我想知道是否有人可以在第一次合并发生时阐明操作的顺序和参数是什

  • 下面的代码给出了最长的回文子序列长度。如何修改代码以获得最长的回文子串长度? 下面是一个示例调用:

  • 我的最新博客地址:我的最新博客 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。 示例 1: 输入: "babad" 输出: "bab" 注意: "aba" 也是一个有效答案。 示例 2: 输入: "cbbd" 输出: "bb" 实现如下: /** * @param {string} s * @return {string} */