【问题标题】:Longest palindromic substring top down dynamic programming最长回文子串自顶向下动态规划
【发布时间】:2018-07-21 19:01:33
【问题描述】:

这是使用自下而上动态规划在给定字符串s 时查找最长回文子串的算法。因此该算法探索所有可能的长度j 子串并检查它是否是1 到n 中j 的有效回文。得到的时间和空间复杂度为O(n^2)

def longestPalindrome(s):
    n = len(s)
    if n < 2:
        return s
    P = [[False for _ in range(n)] for _ in range(n)]
    longest = s[0]

    # j is the length of palindrome
    for j in range(1, n+1):
        for i in range(n-j+1):
            # if length is less than 3, checking s[i] == s[i+j-1] is sufficient
            P[i][i+j-1] = s[i] == s[i+j-1] and (j < 3 or P[i+1][i+j-2])
            if P[i][i+j-1] and j > len(longest):
                longest = s[i:i+j]
    return longest 

我正在尝试以自上而下的方式通过记忆实现相同的算法。

问题: 是否可以将此算法转换为自上而下的方法?

关于最长回文子串的问题有很多,但他们大多使用这种自下而上的方法。 https://stackoverflow.com/a/29959104/6217326 中的答案似乎最接近我的想法。但答案似乎是使用与这个不同的算法(而且速度要慢得多)。

【问题讨论】:

    标签: python dynamic-programming palindrome memoization


    【解决方案1】:

    这是我的递归解决方案: 从 i = 0 开始,j = 最大长度 if(i,j) 是回文:那么最大子串长度是 j-1。 否则使用 (i+1,j) 和 (i, j-1) 进行递归,并在这两者之间取最大值。 代码将解释更多。 代码是用 Java 编写的,但我希望它能给出如何实现它的想法。 @zcadqe 想要了解如何以自上而下的方法实施。我给出了这个想法,并且作为奖励还给出了 java 的代码以便更好地理解。懂python的人都可以轻松转换代码!

    public class LongestPalindromeSubstringWithSubStr {
    static String str;
    static int maxLen;
    static int startLen;
    static int endLen;
    static int dp[][];// 0: not calculaed. 1: from index i to j is palindrome
    
    static boolean isPal(int i, int j) {
        if (dp[i][j] != 0) {
            System.out.println("Res found for i:" + i + " j: " + j);
            return (dp[i][j] == 1);
        }
        if (i == j) {
            dp[i][j] = 1;
            return true;
        }
        if (i + 1 == j) {// len 2
            if (str.charAt(i) == str.charAt(j)) {
                dp[i][j] = 1;
                return true;
            }
            dp[i][j] = -1;
            return false;
        }
        if (str.charAt(i) == str.charAt(j)) {
            boolean res = isPal(i + 1, j - 1);
            dp[i][j] = (res) ? 1 : 0;
            return res;
        }
        dp[i][j] = 0;
        return false;
    }
    
    // update if whole string from i to j is palindrome
    static void longestPalCalc(int i, int j) {
        if (isPal(i, j)) {
            if (j - i + 1 > maxLen) {// update res
                maxLen = j - i + 1;
                startLen = i;
                endLen = j;
            }
        } else {
            longestPalCalc(i + 1, j);
            longestPalCalc(i, j - 1);
        }
    }
    
    public static void main(String[] args) {
        str = "abadbbda";
        dp = new int[str.length()][str.length()];
        longestPalCalc(0, str.length() - 1);
        System.out.println("Longest: " + maxLen);
        System.out.println(str.subSequence(startLen, endLen + 1));
    }
    

    }

    【讨论】:

    • 问题是关于 Python,这是 Java。
    • 那些给予负面评价的人:代码是用Java编写的,但我希望它能给出如何实现它的想法。 @zcadqe 想要了解如何以自上而下的方法实施。我给出了这个想法,并且作为奖励还给出了 java 的代码以便更好地理解。懂python的人都可以轻松转换代码!
    • @BramVanroy:问题不在于 python。问题是:“是否有可能将此算法转换为自上而下的方法?”
    • 阅读标签。问题是关于 Python 的。
    • 如果您对 Java 代码如此不满意,请忽略 Java 部分。有 4 个标签,我已经回答了其中的 3 个,即动态规划、回文、记忆。我相信重点是算法,代码语言根本不重要。
    【解决方案2】:

    这里自顶向下方法的问题是很难实现拓扑顺序。您不能运行 2 for 循环并对其使用记忆,因为此拓扑顺序(2 for 循环)提供子字符串,但它不是回文的正确 TO,因为 3 位回文需要有关它始终位于回文内部的信息(1 位在这种情况)。要知道 a _ _ a 是否是回文,您必须知道 _ _ 是否是回文。因此,您需要的 Topo 顺序是:x,x,xx,xx,xx,xxx,xxx,xxxx,xxxxx 增加长度的子串。 当我编码或获得一个时,我会发布自上而下的方法。

    【讨论】:

      【解决方案3】:
      #include<iostream>
      #include<string>
      #include<vector>
      
      using namespace std;
      
      bool isPalindrome(string str, int startIdx, int stopIdx, vector<vector<int>>& T) {
          const int i = startIdx;
          const int j = stopIdx - 1;
      
          if (i == (j + 1)) {
              return true;
          }
          if (i >= j) {
              return false;
          }
          if (T[i][j] == -1) {
              if (str[i] == str[j]) {
                  T[i][j] = isPalindrome(str, startIdx + 1, stopIdx - 1, T);
              }
              else {
                  T[i][j] = 0;
              }
          }
          return (T[i][j] == 1);
      }
      
      string getLongestStr(string str, int startIdx, int stopIdx, vector<vector<int>>& T) {
          if (isPalindrome(str, startIdx, stopIdx, T)) {
              return str.substr(startIdx, (stopIdx - startIdx));
          }
          else {
              string str1 = getLongestStr(str, startIdx + 1, stopIdx, T);
              string str2 = getLongestStr(str, startIdx, stopIdx - 1, T);
              return str1.size() > str2.size() ? str1 : str2;
          }
          return "";
      }
      
      string getLongestStr(string str) {
          const int N = str.size();
          vector<vector<int>> T(N, vector<int>(N, -1));
          return getLongestStr(str, 0, N, T);
      }
      
      int main() {
          string str = "forgeeksskeegfor";
          //string str = "Geeks";
          
          cout << getLongestStr(str) << endl;
          return 0;
      }
      

      【讨论】:

      • isPalindrome() 函数中有几个条件错误。例如,如果 (i == (j + 1)) { return true; }
      猜你喜欢
      • 2019-05-10
      • 2016-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-26
      • 2015-05-17
      • 2017-02-06
      • 1970-01-01
      相关资源
      最近更新 更多