Leetcode-5. 最长回文串

111 阅读2分钟

题目

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

示例 1:

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

示例 2:

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

示例 3:

输入:s = "a"
输出:"a"

示例 4:

输入:s = "ac"
输出:"a"

来源:力扣(LeetCode)
链接:leetcode-cn.com/problems/lo…
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

结题思路

动态规划
每次计算充分利用之前的计算结果,用空间换时间

核心思想:一个回文串去掉两头以后,剩下的部分依然是回文串

  • 状态 dp[i][j]表示子串s[i...j]是否为回文串

  • 状态转换方程 dp[i][j] = (s[i] == s[j]) && dp[i+1][j-1]

  • 边界条件 除去两边的两个元素后,剩下的元素个数如果小于2(小于等于1),就认为是回文串,不用进行验证。
    即:aba先判断两边是都相等,如果相等就看去除两边后中间元素个数小于2,则是回文数。用下标表示为:
    j-1 - (i+1) + 1 < 2,换算结果为:j - i < 3

  • 初始化 对角线元素只有一个字母,是回文串。
    dp[i][i] = true

  • 输出 得到一个状态为true的时候,记录起始位置和长度,填表完成后进行截取。

这里为什么还需要记录长度?不是在dp表里边记录了么?
实际上,dp表只是记录s[i...j]是不是回文串,他能提供的信息只是是或者不是,因此并不能知道哪个是最长的,以及从哪里开始,因此要记录这写信息,方便之后截取字符串。

算法流程

要时刻明确:动态规划就是维系一张二维表,然后当前结果根据之前计算的结果计算而来,不用重新算 image.png

代码

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];
    // 对角线初始化为true
    for (int i = 0; i < len; i++) {
        dp[i][i] = true;
    }

    char[] charArray = s.toCharArray();
    for (int j = 1; j < len; j++) {
        for (int i = 0; i < j; i++) {
            if (charArray[i] != charArray[j]) {
                // 先判断两边是否相等
                dp[i][j] = false;
            } else {
                // 当子串长度为2或者3的时候不需要进行验证
                if (j - i < 3) {
                    dp[i][j] = true;
                } else {
                    dp[i][j] = dp[i+1][j-1];
                }
            }

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

测试用例

public class Solution_Test_5 {
    Solution_5 solution_5 = new Solution_5();

    @Test
    public void test1() {
        String str = "babad";
        String ans = solution_5.longestPalindrome(str);
        assertEquals(ans, "bab");
    }

    @Test
    public void test2() {
        String str = "cbbd";
        String ans = solution_5.longestPalindrome(str);
        assertEquals(ans, "bb");
    }

    @Test
    public void test3() {
        String str = "a";
        String ans = solution_5.longestPalindrome(str);
        assertEquals(ans, "a");
    }

    @Test
    public void test4() {
        String str = "ac";
        String ans = solution_5.longestPalindrome(str);
        assertEquals(ans, "a");
    }
}