【面试题】最长回文子串

165 阅读1分钟

前言: 本文目的是为了记录并巩固解题思路,希望下次遇到类似的题能想起来=-=

题目如下:

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

示例 1:

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

示例 2:

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

提示:

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

解题:

这道题有很多种解法,暴力、中心扩散、动态规划、manacher算法,是一个经典问题,面试出现频率很高。

首先我们尝试动态规划算法,它的复杂度是O(n²),比中心扩散法(O(n^3))要快一些

一般来说,用动态规划解题之前需要准备4个步骤

  1. 确定状态
  • 子问题:s[i,j]是否是回文子串(i代表左边界,j代表右边界)
  • 最后一个状态:true|false,代表是否是回文串
  1. 构建状态转移方程
  • dp[i , j] = dp[i + 1 ][j - 1]

    这个状态很容易理解,例如:**'cabac'**这个例子 判断s[0,4]是否是回文串,需要要基于s[1,3]是否是回文串来决定 如果s[1,3]不是回文串,那s[0,4]必然不是。 所以当s[0]==s[4]时,如果s[1,3]是回文串,那么s[0,4]就可以确定是回文串

  1. 初始值、边界
  • dp[x][x] 都是true,因为它是单个字符,符合回文串规定
  • 如果s[i] == s[j] 并且 j - i + 1 <= 3 时,可以直接给dp[i][j]赋值为true 因为当s[i,j]的长度等于0或1时,它就是回文串 当s[i,j]的长度等于2或3时,由于左右相等,所以它也是回文串
  1. 计算顺序 dp[i,j] 需要基于 dp[i+1][j-1]的状态,

    如果此时构建一个二维表格,j为x轴,i为y轴。会发现,每个格子需要的状态来自于当前格子左下方的格子

    因为:

    x轴 -> j - 1 y轴 -> i + 1

    同时,从左上角到右下角的值,都是true(因为dp[x][x] = true)。

    所以计算顺序应该从左上角开始,向右、下方更新表的状态

接下来我们来实现一下:


function longestPolinDrome(s) {
    const len = s.length;
    
    // 如果长度为0、1,则根据题意,可以直接返回
    if (len <= 1) {
        return s;
    }
    
    // 以空间换时间,创建二维表,缓存所有子问题的最优状态
    const dp = new Array(len).fill(false).map(()=>new Array(len).fill(false));
    
    // 初始化状态
    for(let i = 0;i < len; i++) {
        dp[i][i] = true;
    }
    
    let maxLen = 0, begin = -1;
    
    // x轴从1开始填表,因为dp[0,0]已经是true了
    for (let j = 1;j < len; j++) {
        //y轴上,从上到下填表
        for (let i = 0;i < j; i++) {
            if (s[j] !== s[i]) {
                dp[i][j] = false;
            } else {
                // 当左边等于右边,并且长度为0,1,2,3时,那么i~j就是个回文串
                if (j - i + 1 <= 3 ){
                    dp[i][j] = true;
                }else {
                    dp[i][j] = dp[i+1][j-1];
                }
            }
        }
        
        if (dp[i][j] && j - i + 1 > maxLen){
           maxLen = j - i + 1;
           begin = i;
        }
    }
    
    if(begin >= 0) {
        return s.subStr(begin, maxLen);
    }
    return s[0];
}