最长回文子串自上而下的动态编程

时间:2018-07-21 19:01:33

标签: python dynamic-programming palindrome memoization

这里是使用自底向上的动态编程查找给定字符串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中的答案似乎与我所想的最接近。但是答案似乎是使用与此算法不同的算法(而且速度较慢)。

2 个答案:

答案 0 :(得分: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));
}

}

答案 1 :(得分:0)

#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;
}