每日算法-最长回文串(中等-动态规划)

364 阅读4分钟

题目

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

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

示例 2:

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

示例 3:

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

示例 4:

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

暴力法:一目了然

function longestPalindrome(s) {
  int len = s.length;
  if (len < 2) {
      return s;
  }
  int maxLen = 1;
  let res = s.substring(01);
  // 枚举所有长度大于等于 2 的子串
  for (let i = 0; i < len - 1; i++) {
    for (let j = i + 1; j < len; j++) {
        if (j - i + 1 > maxLen && valid(s, i, j)) {
          maxLen = j - i + 1;
          res = s.substring(i, j + 1);
        }
    }
  }
  return res;
}

function valid(s, left, right) {
    // 验证子串 s[left, right] 是否为回文串
    while (left < right) {
        if (s[left] != s[right]) {
            return false;
        }
        left++;
        right--;
    }
    return true;
}
}

方法一:动态规划

  • 如果一个字符串是回文串,那么在它左右分别加上一个相同的字符,那么它一定还是一个回文串
  • 如果在一个不是回文字符串的字符串两端添加任何字符,或者在回文串左右分别加不同的字符,得到的一定不是回文串 使用dp[i][j] 表示 s 中从 i 到 j(包括 i 和 j)是否可以形成回文,将上面的描述转化为代码:
if (s[i] === s[j] && dp[i + 1][j - 1]) {
  dp[i][j] = true;
}
/**
 * @param {string} s
 * @return {string}
 */
var longestPalindrome = function (s) {
  let n = s.length;
  let dp = Array.from(new Array(n), () => new Array(n).fill(0)); // 初始化二维数组用于记录dp[i][j]是否为true
  let res = "";
  for (let i = n - 1; i >= 0; i--) { // 从字符串的末尾开始构建dp[i][j]
    for (let j = i; j < n; j++) {
      dp[i][j] = s[i] == s[j] && (j - i < 2 || dp[i + 1][j - 1]);
      if (dp[i][j] && j - i + 1 > res.length) {
        res = s.substring(i, j + 1);
      }
    }
  }
  return res;
}

方法二: 中心扩张

如图:

function longestPalindrome1(s) {
    if (s == null || s.length == 0) {
        return "";
    }
    let strLen = s.length();
    let left = 0;
    let right = 0;
    let len = 1;
    let maxStart = 0;
    let maxLen = 0;

    for (let i = 0; i < strLen; i++) {
        left = i - 1;
        right = i + 1;
        while (left >= 0 && s[left] == s[i]) {
            len++;
            left--;
        }
        while (right < strLen && s[]right] == s[i]) {
            len++;
            right++;
        }
        while (left >= 0 && right < strLen && s[right] == s[left]) {
            len = len + 2;
            left--;
            right++;
        }
        if (len > maxLen) {
            maxLen = len;
            maxStart = left;
        }
        len = 1;
    }
    return s.substring(maxStart + 1, maxStart + maxLen + 1);
}