编程 如何在 JavaScript 字符串中找到最长的回文子字符串?

2025-06-28 17:55:21 +0800 CST views 36

如何在 JavaScript 字符串中找到最长的回文子字符串?

在字符串处理问题中,回文字符串(Palindrome) 是一种非常经典的模式:一个字符串如果正着读和反着读完全一样,它就是回文字符串,例如 'racecar''abba'

在实际开发中,我们经常需要找到一个字符串中最长的回文子字符串(Longest Palindromic Substring),这不仅考验我们的算法能力,也训练我们对于双指针、中心扩展等技术的掌握。

⚠ 本文不涉及 Manacher 算法(最优 O(n) 解决方案),而是注重于常见算法思维和实战技巧的掌握。


🔍 一、什么是回文字符串?

判断一个字符串是否是回文非常简单。可以直接反转它然后与原始字符串进行比较:

const isPalindrome = str => {
  const reversed = str.split('').reverse().join('');
  return str === reversed;
};

isPalindrome('racecar'); // true
isPalindrome('abba');    // true
isPalindrome('hello');   // false

🧨 二、暴力破解法(Brute Force)

最直观的方式是穷举所有可能的子字符串,然后依次判断它们是否是回文,保留其中最长的那一个。

实现思路:

  1. 使用两个指针枚举所有子串。
  2. 检查是否为回文。
  3. 更新最长结果。
const longestPalindrome = str => {
  let best = { length: 0, value: '' };
  for (let l = 0; l < str.length; l++)
    for (let r = l + best.length; r < str.length; r++) {
      const current = { length: r - l, value: str.slice(l, r + 1) };
      if (!isPalindrome(current.value)) continue;
      if (current.length < best.length) continue;
      best = current;
    }
  return best.value;
};

longestPalindrome('babad'); // 输出 'bab' 或 'aba'
longestPalindrome('cbbd');  // 输出 'bb'

复杂度分析

  • 时间复杂度:O(n^3)
  • 空间复杂度:O(n)(字符串切片时)

❗暴力法虽然直观,但效率非常低,无法应对大规模数据。


💡 三、中心扩展法(Expand Around Center)

我们可以将每个字符(甚至字符间的空隙)作为“回文中心”,从中心向两边扩展,查找最大长度的回文。

回文扩展核心函数:

const expandAroundCenter = (str, left, right) => {
  while (left >= 0 && right < str.length && str[left] === str[right]) {
    left--;
    right++;
  }
  return {
    left: left + 1,
    right: right - 1,
    length: right - left - 1
  };
};

判断字符串是否为回文:

const isPalindrome = str => {
  const centerPoints = (str.length % 2 === 0)
    ? [str.length / 2 - 1, str.length / 2]
    : [Math.floor(str.length / 2), Math.floor(str.length / 2)];
  const maxPalindrome = expandAroundCenter(str, ...centerPoints);
  return maxPalindrome.length === str.length;
};

🚀 四、最终高效实现(推荐方法)

将中心扩展方法应用到字符串的每一个位置,以捕获最长的回文子串。

const expandAroundCenter = (str, left, right) => {
  while (left >= 0 && right < str.length && str[left] === str[right]) {
    left--;
    right++;
  }
  return { left: left + 1, right: right - 1, length: right - left - 1 };
};

const longestPalindrome = str => {
  let best = { left: 0, right: 0, length: 0 };
  for (let i = 0; i < str.length; i++) {
    const odd = expandAroundCenter(str, i, i);
    const even = expandAroundCenter(str, i, i + 1);
    const current = odd.length > even.length ? odd : even;
    if (current.length > best.length) best = current;
  }
  return str.slice(best.left, best.right + 1);
};

longestPalindrome('babad'); // 输出 'bab' 或 'aba'
longestPalindrome('cbbd');  // 输出 'bb'

复杂度分析

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

🧠 五、总结与启发

我们一步步从最基础的暴力破解,优化到基于中心扩展的高效解法。虽然这并非理论上的最优(Manacher 算法可达到 O(n)),但在实际开发中已足够高效且易于实现。

技术要点回顾:

  • 双指针技巧 在字符串问题中极其重要。
  • 从中心扩展法 是解决对称性问题的通用思路。
  • 不要一开始就追求最优算法,先实现可行解再逐步优化
复制全文 生成海报 算法 字符串处理 JavaScript

推荐文章

利用Python构建语音助手
2024-11-19 04:24:50 +0800 CST
快速提升Vue3开发者的效率和界面
2025-05-11 23:37:03 +0800 CST
资源文档库
2024-12-07 20:42:49 +0800 CST
Python设计模式之工厂模式详解
2024-11-19 09:36:23 +0800 CST
ElasticSearch 结构
2024-11-18 10:05:24 +0800 CST
api接口怎么对接
2024-11-19 09:42:47 +0800 CST
PHP 压缩包脚本功能说明
2024-11-19 03:35:29 +0800 CST
在 Nginx 中保存并记录 POST 数据
2024-11-19 06:54:06 +0800 CST
pip安装到指定目录上
2024-11-17 16:17:25 +0800 CST
go错误处理
2024-11-18 18:17:38 +0800 CST
跟着 IP 地址,我能找到你家不?
2024-11-18 12:12:54 +0800 CST
页面不存在404
2024-11-19 02:13:01 +0800 CST
2025年,小程序开发到底多少钱?
2025-01-20 10:59:05 +0800 CST
Vue3中如何进行异步组件的加载?
2024-11-17 04:29:53 +0800 CST
mysql关于在使用中的解决方法
2024-11-18 10:18:16 +0800 CST
宝塔面板 Nginx 服务管理命令
2024-11-18 17:26:26 +0800 CST
Nginx 状态监控与日志分析
2024-11-19 09:36:18 +0800 CST
Grid布局的简洁性和高效性
2024-11-18 03:48:02 +0800 CST
H5端向App端通信(Uniapp 必会)
2025-02-20 10:32:26 +0800 CST
百度开源压测工具 dperf
2024-11-18 16:50:58 +0800 CST
markdown语法
2024-11-18 18:38:43 +0800 CST
Vue3中如何扩展VNode?
2024-11-17 19:33:18 +0800 CST
程序员茄子在线接单