夯实算法-14.最长回文子串

142 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第24天,点击查看活动详情

题目:LeetCode

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

示例 1:

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

示例 2:

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

示例 3:

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

示例 4:

输入:s = "ac"
输出:"a"
解释: "c" 同样是符合题意的答案。

提示:

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

解题思路

题目求最长回文子串,算法题练习多了,对于本题其实很自然就想到动态规划方法来解。
直接按照动态规划步骤来:

  • 定义一个dp数组,确定其下标所表示的含义
    dp[i][j]:表示区间[i,j](左闭右闭)子串是否为回文子串,若是 dp[i][j]为true,否则为false

回文子串1.jpeg

  • 推导出递推公式
    要确定递推公式,需考虑两种情况:(1)s[i]与s[j]相等,(2)s[i]与s[j]不相等

    • s[i]与s[j]不相等时,dp[i][j]必定为false
    • s[i]与s[j]相等时,会有三种不同情况:
      • 下标i 与 j相同,表示同一个字符(例如a),肯定是回文子串
      • 下标i 与 j相差为1,如:aa,也是回文子串
      • i 与 j相差大于1时,s[i]与s[j]已经相同,只需要确定dp[i + 1][j - 1]是否为true即可
        s[i] 和 s[j] 相等,并且子串 i+1..j-1 是回文串的话,子串 i..j 肯定也是回文串。即:如果 s[i] == s[j] 且 dp[i+1][j-1] = true 时,dp[i][j] = true
  • dp数组初始化值: dp[i][j]初始化应为false

  • 遍历顺序

    • 首先从递推公式中可以看出,根据dp[i + 1][j - 1]是否为true,再对dp[i][j]进行赋值true
    • 要从下到上,从左到右遍历,确保dp[i + 1][j - 1]都经过计算
  • 根据递推公式确认dp数组所有元素

    • dp[i][j]的定义,所以j一定是大于等于i的,那么在填充dp[i][j]的时候一定是只填充右上半部分

longest-palindromic-substring-dp-2-5.jpeg

代码实现

    public String longestPalindrome(String s) {
        if (s.isEmpty()) {  // 判空校验 
            return s;
        }
        int n = s.length();
        boolean[][] dp = new boolean[n][n];  // 创建二维数组dp
        int left = 0;
        int right = 0;
        for (int i = n - 2; i >= 0; i--) {
            dp[i][i] = true;
            for (int j = i + 1; j < n; j++) {
                //小于3是因为aba一定是回文
                dp[i][j] = s.charAt(i) == s.charAt(j) &&( j-i<3||dp[i+1][j-1]);
                
                if(dp[i][j]&&right-left<j-i){ // 更新区间边界
                    left=i;
                    right=j;
                }
            }
        }
        return s.substring(left,right+1);
    }

运行结果

Snipaste_2022-08-24_11-55-25.png

复杂度分析

  • 时间复杂度 O(n2)O(n^2)
  • 空间复杂度 O(n2)O(n^2)

掘金(JUEJIN)  一起分享知识, Keep Learning!