算法初探LeetCode-最长回文子串

81 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第11天,点击查看活动详情

LeetCode15:最长回文子串

给你一个字符串 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.png

  • 推导出递推公式
    要确定递推公式,需考虑两种情况:(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]的时候一定是只填充右上半部分

2.png

算法代码

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

算法复杂度

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

掘金(JUEJIN)一起进步,一起成长!