LeetCode热题(JS版)- 5. 最长回文子串

153 阅读1分钟

题目

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

示例 1:

输入: s = "babad"
输出: "bab"
解释: "aba" 也是一个有效解

示例 2:

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

解法1:中心扩散法

  • 思路
    • 从0-length查找
    • 每次找的时候分奇数偶数,如果当前1/2个字符相同,且前后字符相同则向外扩展
    • 找出后进行比较,更新最大值
  • 时间复杂度:O(n^2)
  • 代码
function longestPalindrome(s: string): string {
    // 长度范围 0 - length
    const { length } = s;
    let max = 0, res = '';
    
    const find = (l, r) => {
        let str = '';
        // 当前1/2个元素要相同
        if(s[l] !== s[r]) {
            return { len: 0, l, r: l }
        }

        // 两侧相等则扩展
        while(l > 0 && r < length - 1 && s[l - 1] === s[r + 1]){
            l--;
            r++;      
        }
        
        return {
            len: r - l + 1,
            l, r
        }
    };
    
    const update = ({ len, l, r }) => {
        if(len > max) {
            max = len;
            res = s.slice(l, r + 1);
        }
    }
    
    for(let i = 0; i < length; i++) {
        // 奇数,找以i为中心的回文子串
        update(find(i, i));
        // 偶数,找以i,i+1为中心的回文子串
        update(find(i, i + 1));
    }
    
    return res;
};

image.png

解法2:动态规划

我们可以使用动态规划来解决此问题。首先定义状态 dp[i][j] 表示字符串 s 中第 i 到 j 个字符组成的子串是否是回文串。如果是回文串,则 dp[i][j] 的值为 true,否则为 false。

接下来考虑状态转移方程。当 s[i] == s[j] 时,只有当 dp[i+1][j-1] 为 true 时,dp[i][j] 才可能为 true。当 s[i] != s[j] 时,dp[i][j] 必然为 false。同时还需要注意一些边界条件,即当 i >= j 或 j - i <= 2 时,dp[i][j] 必然为 true。

最后遍历二维数组 dp,并记录下最长回文子串的起始位置和长度,即可得到最长回文子串。

function longestPalindrome(s: string): string {
    const len = s.length;
    if (len < 2) {
        return s;
    }
    let start = 0, maxLen = 1;
    const dp: boolean[][] = Array.from({ length: len }, () => new Array(len).fill(false));
    for (let i = 0; i < len; i++) {
        dp[i][i] = true;
    }
    for (let j = 1; j < len; j++) {
        for (let i = 0; i < j; i++) {
            if (s[i] === s[j]) {
                if (j - i <= 2) {
                    dp[i][j] = true;
                } else {
                    dp[i][j] = dp[i + 1][j - 1];
                }
            } else {
                dp[i][j] = false;
            }
            if (dp[i][j] && j - i + 1 > maxLen) {
                start = i;
                maxLen = j - i + 1;
            }
        }
    }
    return s.substring(start, start + maxLen);
}
  • 时间复杂度为 O(n2)O(n^2),其中 nn 是字符串的长度。原因是我们需要遍历二维数组 dp 中的所有元素,并计算出其值。
  • 空间复杂度为 O(n2)O(n^2),其中 nn 是字符串的长度。原因是我们需要使用一个二维数组 dp 来存储子串是否为回文串的状态。

解法3:manacher方法

TODO