【LeetCode刷题记录】5.最长回文子串

92 阅读1分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

一、题目描述:

题目来源:LeetCode-最长回文子串

给你一个字符串 s,找到 s 中最长的回文子串。

示例 1:

输入:s = "babad" 输出:"bab" 解释:"aba" 同样是符合题意的答案。 示例 2:

输入:s = "cbbd" 输出:"bb"  

提示:

1 <= s.length <= 1000 s 仅由数字和英文字母组成

二、思路分析:

思路: 暴力破解

暴力求解,列举所有的子串,判断是否为回文串,保存最长的回文串。

三、AC 代码:

public String longestPalindrome(String s) {
    String result = "";
    int max = 0;
    int len = s.length();
    for (int i = 0; i < len; i++)
        for (int j = i + 1; j <= len; j++) {
            String test = s.substring(i, j);
            if (isPalindromic(test) && test.length() > max) {
                result = s.substring(i, j);
                max = Math.max(max, result.length());
            }
        }
    return result;
}
    
public boolean isPalindromic(String s) {
    int len = s.length();
    for (int i = 0; i < len / 2; i++) {
        if (s.charAt(i) != s.charAt(len - i - 1)) {
            return false;
        }
    }
    return true;
}

四、总结:

参考liweiwei1419的答案,可以使用动态规划的思想解答题目。

动态规划: 回文天然具有「状态转移」性质:一个长度严格大于 22 的回文去掉头尾字符以后,剩下的部分依然是回文。反之,如果一个字符串头尾两个字符都不相等,那么这个字符串一定不是回文。「动态规划」的方法根据这样的性质得到。

第 1 步:定义状态 dp[i][j] 表示: 子串 s[i..j]是否为回文子串 这里子串 s[i..j]定义为左闭右闭区间,即可以取到 s[i] 和 s[j]。

第 2 步:思考状态转移方程 根据头尾字符是否相等,需要分类讨论:

dp[i][j] = (s[i] == s[j]) and dp[i + 1][j - 1]

第 3 步:考虑初始化 单个字符一定是回文串,因此把对角线先初始化为 true,即 dp[i][i] = true。根据第 2 步的说明:当 s[i..j] 的长度为 22 时,只需要判断 s[i] 是否等于 s[j],所以二维表格对角线上的数值不会被参考。所以不设置 dp[i][i] = true 也能得到正确结论。

第 4 步:考虑输出 一旦得到 dp[i][j] = true,就记录子串的「长度」和「起始位置」。没有必要截取,这是因为截取字符串也有性能消耗。

public class Solution {

    public String longestPalindrome(String s) {
        // 特殊用例判断
        int len = s.length();
        if (len < 2) {
            return s;
        }

        int maxLen = 1;
        int begin = 0;

        // dp[i][j] 表示 s[i, j] 是否是回文串
        boolean[][] dp = new boolean[len][len];
        char[] charArray = s.toCharArray();

        for (int i = 0; i < len; i++) {
            dp[i][i] = true;
        }
        for (int j = 1; j < len; j++) {
            for (int i = 0; i < j; i++) {
                if (charArray[i] != charArray[j]) {
                    dp[i][j] = false;
                } else {
                    if (j - i < 3) {
                        dp[i][j] = true;
                    } else {
                        dp[i][j] = dp[i + 1][j - 1];
                    }
                }

                // 只要 dp[i][j] == true 成立,就表示子串 s[i..j] 是回文,此时记录回文长度和起始位置
                if (dp[i][j] && j - i + 1 > maxLen) {
                    maxLen = j - i + 1;
                    begin = i;
                }
            }
        }
        return s.substring(begin, begin + maxLen);
    }
}