Dynamic Programming学习笔记 (16) - 最长回文子串 (力扣# 5)

157 阅读1分钟

最长回文子串问题与最长回文子序列问题类似,其不同之处在于回文子序列允许从原字串中删去若干个字符,而回文子串则不可以,其题面为

给定一个长度为N的字符串s,找到s中最长的回文子串。

实例如下:

s = "babad"
答案为"bab"或是"aba"

解题思路:

我们可以定义一个表达式F(i, j),其中i是字符串的开始下标,j是结束下标,F(i, j)返回的是从i到j的子字符串是否是回文子串。

根据题面的要求,我们有以下两种情况

  1. s[i]与s[j]相同,在该情况下,如果i和j相同,i+1=j或者i+2=j,那么F(i, j)返回的就是True, 否则返回F(i + 1, j - 1)
  2. s[i]与s[j]不同,在该情况下,F(i, j)返回的False

边界情况是当i>j时,F(i, j)始终返回False。

从以上表达式出发,我们可以定义一个(N+1) * (N+1)的二维数组作为DP存储,然后使用双重循环,外层循环依据字串下标从大到小,内层循环依据字串下标从小到大,来依次计算DP数组中各个元素的值。并比较所有回文子串的长度以找到最长的一个。

Java代码如下

class Solution {
    public String longestPalindrome(String s) {
        char[] chars = s.toCharArray();
        int N = chars.length;

        int maxLen = 1;
        int maxStart = 0;

        boolean[][] dp = new boolean[N + 1][N + 1];

        for (int i = N; i >= 1; i --) {
            dp[i][i] = true;
            for (int j = i + 1; j <= N; j ++) {
                if ((chars[i - 1] == chars[j - 1])) {
                    if ( j - i <= 2  || dp[i + 1][j - 1]) {
                        dp[i][j] = true;
                        int len = j - i + 1;
                        if (len > maxLen) {
                            maxLen = len;
                            maxStart = i - 1;
                        }
                    }
                }
            }
        }

        return s.substring(maxStart, maxStart + maxLen);
    }
}