返回

探究JS算法之最长回文子串,纵览算法之美

前端

查找字符串中最长回文子串的算法

回文,一个从左到右读与从右到左读都一样的字符串,就像一面镜子中的倒影。在计算机科学中,查找字符串中最长回文子串是一个经典且实用的问题。本文将深入探讨两种不同的算法,引导你踏上发现最长回文子串的旅程。

动态规划法:自底向上,逐步求解

动态规划算法将问题分解为更小的子问题,依次解决它们。它引入了一个二维表 dp,其中 dp[i][j] 记录了字符串 s 从位置 i 到位置 j 的子串是否是回文。

算法从左上角开始,逐行逐列填充表格。当遇到 dp[i][j] 时,它检查子串是否回文,如果是则设为 1,否则设为 0

中心扩展法:从中心向两边探索

中心扩展算法以每个字符为中心,向两边扩展回文边界。它有两种情况:

  1. 奇数长度回文:中心是一个字符。
  2. 偶数长度回文:中心是两个相邻字符。

对于每种情况,算法从中心向外扩展,直到字符不匹配或到达字符串边界。

代码示例

动态规划法

function longestPalindrome_DP(s) {
  if (!s) return "";
  let longestPalindrome = "";
  let start = 0, end = 0;

  const dp = new Array(s.length).fill(0).map(() => new Array(s.length).fill(0));

  for (let i = 0; i < s.length; i++) {
    dp[i][i] = true;
  }

  for (let i = s.length - 1; i >= 0; i--) {
    for (let j = i + 1; j < s.length; j++) {
      if (s[i] === s[j] && (j - i <= 2 || dp[i + 1][j - 1])) {
        dp[i][j] = true;
        if (j - i + 1 > end - start + 1) {
          start = i;
          end = j;
        }
      }
    }
  }

  return s.substring(start, end + 1);
}

中心扩展法

function longestPalindrome_CenterExpansion(s) {
  if (!s) return "";
  let longestPalindrome = "";
  let start = 0, end = 0;

  for (let i = 0; i < s.length; i++) {
    let [l, r] = [i, i];
    while (l >= 0 && r < s.length && s[l] === s[r]) {
      if (r - l + 1 > end - start + 1) {
        start = l;
        end = r;
      }
      l--;
      r++;
    }
  }

  for (let i = 0; i < s.length - 1; i++) {
    let [l, r] = [i, i + 1];
    while (l >= 0 && r < s.length && s[l] === s[r]) {
      if (r - l + 1 > end - start + 1) {
        start = l;
        end = r;
      }
      l--;
      r++;
    }
  }

  return s.substring(start, end + 1);
}

比较

  • 时间复杂度:动态规划法为 O(n^2),中心扩展法也为 O(n^2)。
  • 空间复杂度:动态规划法需要额外的空间 O(n^2) 存储表格 dp,而中心扩展法只需要 O(1) 的额外空间。
  • 适用性:中心扩展法更适合处理超长字符串,因为它不会创建巨大的表格。

常见问题解答

  1. 这些算法只能处理 ASCII 字符吗?

    • 不,这些算法可以处理 Unicode 字符。
  2. 算法是否可以处理重叠的回文?

    • 是的,这些算法可以找到所有重叠的回文。
  3. 是否有更高效的算法?

    • 目前还没有已知的时间复杂度低于 O(n^2) 的算法。
  4. 如何处理有空格或其他分隔符的字符串?

    • 可以预处理字符串,删除所有空格和分隔符,然后运行算法。
  5. 算法是否可以处理多行字符串?

    • 可以通过将字符串处理成单行文本,然后运行算法来处理多行字符串。