【算法题系列】LeetCode 5.最长回文子串|JavaScript 5种思路实现
题目描述
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: "babad" 输出: "bab" 注意: "aba" 也是一个有效答案。
示例 2:
输入: "cbbd" 输出: "bb"
题解
回文:指一个正读和反读都相同的字符串,例如,“aba” 是回文,而 “abc” 不是。
解决方案
思路一:暴力法
即通过双重遍历来获取目标字符串所有的子串,push 到一个数组里面,然后根据字符串长度排序,从最长字串开始循环校验,第一个为回文的子串就是我们要的结果
复杂度分析
- 时间复杂度:O(n^3)
- 空间复杂度:O(1)
/*** @param {string} s* @return {string}*/
var longestPalindrome = function(s) {let m = []let res = ''for(let i=0; i<s.length; i++) {for(let j = i; j < s.length; j++) {m.push(s.slice(i, j+1))}}m.sort(function(a,b){return b.length - a.length})for (let i of m) {if (i === i.split('').reverse().join('')) {res = ibreak;}}return res
}
上面代码在目标字符串长度过大的时候,会超出时间限制,远远超出O(n^2) 的理想时间复杂度,这是因为过多的for 循环,js 自带函数使用过多造成的,优化一下
var longestPalindrome = function(s) {let m = []let res = ''for(let i=0; i<s.length; i++) {for(let j = i; j < s.length; j++) {if (s[i] != s[j]) breaklet ele = s.slice(i, j+1)if (ele === ele.split('').reverse().join('') && ele.length > res.length) {res = ele}}}return res
}
看起来好多了,但是依然通不过Leecode 的测试,我觉得必须要把 slice split reverse join 这些函数都干掉才行,也可能 JS 语言效率确实慢一些
思路二:最长公共字串
反转 S,使之变成 S'。找到 S 和 S' 之间最长的公共子串,判断是否是回文
复杂度分析
- 时间复杂度:O(n^2)
- 空间复杂度:O(n^2)
/*** @param {string} s* @return {string}*/
var longestPalindrome = function(s) {let rs = s.split('').reverse().join('')let size = s.lengthlet len = 0let end = 0let a = new Array(size)for (let i = 0; i < size; i++) {a[i] = new Array()}for (let i = 0; i < size; i++) {for(let j = 0; j < size; j++) {if (s[i] === rs[j]) {if (i > 0 && j > 0) {a[i][j] = a[i-1][j-1] + 1} else {a[i][j] = 1}if(a[i][j] > len) {let beforeIndex = size - 1 - jif (beforeIndex + a[i][j] -1 == i) { len = a[i][j]end = i}}} else {a[i][j] = 0}}}return s.slice(end-len+1, end+1)
}
思路三:中心拓展
遍历一遍字符串,以每个字符为中心向两边判断,是否为回文字符串
复杂度分析
- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
/*** @param {string} s* @return {string}*/
var longestPalindrome = function(s) {let size = s.lengthlet start = 0let len = 0 //字串长度// 奇数长度的回文字串for (let i = 0; i < size; i++) {let left = i - 1let right = i + 1while (left >= 0 && right < size && s[left] == s[right]) {left --right ++}if (right - left - 1 > len) {start = left +1len = right -left -1}}// 偶数长度的回文字串for (let i = 0; i < size; i++) {let left = ilet right = i + 1while (left >= 0 && right < size && s[left] == s[right]) {left--right++}if (right -left -1 > len) {start = left + 1len = right -left -1}}return s.slice(start, start + len)
}
思路四:动态规划
思路五:Manacher 算法
manacher 算法涉及中心拓展法、动态规划,是manacher 1975年发明出来用来解决最长回文子串的线性算法
// 第一步
var longestPalindrome = function(s) {let size = s.lengthif (size < 2) {return s}let str = addBoundaries(s, '#')let formatSize = 2 * size +1let maxSize = 1let start = 0for (let i=0; i<formatSize; i++) {let curSize = centerSpread(str, i)if (curSize > maxSize) {maxSize = curSizestart = (i - maxSize)/2}}return s.slice(start, start + maxSize)
}// 处理原字符串
var addBoundaries = function(s, divide) {let size = s.lengthif (size === 0) {return ''}if (s.indexOf(divide) != -1) {throw new Error('参数错误,您传递的分割字符,在输入字符串中存在!')}return divide + s.split('').join(divide) + divide
}// 辅助数组
var centerSpread = function(s, center) {// left = right 的时候,此时回文中心是一个空隙,回文串的长度是奇数// right = left + 1 的时候,此时回文中心是任意一个字符,回文串的长度是偶数let len = s.lengthlet i = center - 1let j = center + 1let step = 0while (i >= 0 && j < len && s.charAt(i) == s.charAt(j)) {i--j++step++}return step
}
longestPalindrome('ababadfglldf;hk;lhk')
manacher 算法的工作,就是对上面代码中的辅助数组 p 进行优化,使时间复杂度的降到O(n^2)
// 完整
var longestPalindrome = function(s) {let size = s.lengthif (size < 2) {return s}let str = addBoundaries(s, '#')let formatSize = 2 * size +1let p = new Array(formatSize).fill(0)let maxRight = 0let center = 0let maxSize = 1let start = 0for (let i=0; i<formatSize; i++) {if (i < maxRight) {let mirror = 2 * center - i;// Manacher 算法的核心p[i] = Math.min(maxRight - i, p[mirror]);}// 下一次尝试扩散的左右起点,能扩散的步数直接加到 p[i] 中let left = i - (1 + p[i]);let right = i + (1 + p[i]);// left >= 0 && right < formatSize 保证不越界// str.charAt(left) == str.charAt(right) 表示可以扩散 1 次while (left >= 0 && right < formatSize && str.charAt(left) == str.charAt(right)) {p[i]++;left--;right++;}// 根据 maxRight 的定义,它是遍历过的 i 的 i + p[i] 的最大者// 如果 maxRight 的值越大,进入上面 i < maxRight 的判断的可能性就越大,这样就可以重复利用之前判断过的回文信息了if (i + p[i] > maxRight) {// maxRight 和 center 需要同时更新maxRight = i + p[i];center = i;}if (p[i] > maxSize) {// 记录最长回文子串的长度和相应它在原始字符串中的起点maxSize = p[i];start = (i - maxSize) / 2;}}return s.slice(start, start + maxSize)
}var addBoundaries = function(s, divide) {let size = s.lengthif (size === 0) {return ''}if (s.indexOf(divide) != -1) {throw new Error('参数错误,您传递的分割字符,在输入字符串中存在!')}return divide + s.split('').join(divide) + divide
}
longestPalindrome('babb')
参考链接:manacher 算法
文章更新平台:掘金、知乎。
相关文章:
【算法题系列】LeetCode 5.最长回文子串|JavaScript 5种思路实现
题目描述 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。 示例 1: 输入: "babad" 输出: "bab" 注意: "aba" 也是一个有效答案。 示例 2: 输入: "cbbd" 输出: &q…...
基于ROS先验地图的机器人自主定位与导航SLAM
2021年学习,当时参加科大讯飞的智能车大赛, 【语音交互启动-teb算法路径规划A*算法自动避障路径最短优化yolo5目标检测视觉结果判断分类终点指定点位自动泊车语音播报。】 【讯飞学院】http://www.iflyros.com/home/ 一、全局路径规划中的地图 栅格地图&…...
nginx 1.6.3配置虚拟主机与rewrite-location匹配规则
1、 Nginx 虚拟主机配置(配置文件末尾以分号[;]结尾) (1) 准备测试目录站点 [rootWEB conf]# cd /application/nginx/conf/ [rootWEB conf]# mkdir extra (创建虚拟主机存放目录࿰…...

1130-host ... is not allowed to connect to this MySql serve
局域网内另外一台电脑使用navicat连接Mysql出现上述问题:不允许连接 解决方案: 1、输入命令:进入mysql mysql -u root -p 2、输入命令:展示所有数据库 show databases; 3、输入命令进入mysql数据库: use mysql; 4、…...

力扣1502判断能否形成等差数列
class Solution:def canMakeArithmeticProgression(self, arr: List[int]) -> bool:# 对数组进行排序arr.sort()# 计算公差diff arr[1] - arr[0]# 从第二个元素开始逐个检查差值是否一致for i in range(1, len(arr) - 1):if arr[i 1] - arr[i] ! diff:return Falsereturn …...
Python版本变更历史及版本选择指南
Python版本变更历史及版本选择指南 Python版本变更历史及版本选择指南1. Python 3.13.1(2023年发布)主要特性适用场景 2. Python 3.12(2022年发布)主要特性 3. Python 3.11(2022年发布)主要特性 4. Python …...
初始值变量类型
状态名同步位置初始值变量类型不支持的UL刷新注意事项State父组件必填Object、classstring、number、boolean、enum类型,以及这些类型的数组。支持Date类型。对象的对象数组属性更新数组对象的属性更新 State装饰的变量必须初始化,否则编译期会报错。Sta…...
苍穹外卖 项目记录 day03
文章目录 菜品管理模块开发公共字段填充自定义注解 AutoFill自定义切面 AutoFillAspect在Mapper接口的方法上加入 AutoFill 注解 新增菜品文件上传实现新增菜品实现菜品分页查询删除菜品实现修改菜品实现 菜品管理模块开发 公共字段填充 在新增员工或者新增菜品分类时需要设置…...
统计字符【2】(PTA)C语言
本题要求编写程序,输入N个字符,统计其中英文字母、空格或回车、数字字符和其他字符的个数。 输入格式: 输入在第一行中给出正整数N,第二行输入N个字符,最后一个回车表示输入结束,不算在内。 输出格式: 在一行内按照…...
如何在 Spring Cloud Gateway 中创建全局过滤器、局部过滤器和自定义条件过滤器
Spring Cloud Gateway 是一个功能强大的 API 网关,能够处理 HTTP 请求、响应及路由。通过过滤器机制,您可以在请求和响应过程中进行各种处理操作,如记录日志、身份验证、限流等。Spring Cloud Gateway 提供了三种主要类型的过滤器:…...
PINN模型详解
定义与原理 物理信息神经网络(Physics-Informed Neural Networks, PINN)是一种创新性的机器学习模型,巧妙地将物理知识与深度学习相结合。这种独特的设计理念源于Karniadakis教授的研究团队,他们在一系列开创性工作中提出了这一概念。 PINN的核心思想是在神经网络的损失函数…...

查找路由器的管理后台ip【通用找IP】
需求: 刚刚搞了个【小米】路由器,我想进路由的管理后台,提示:安装xx的路由管家,我不想安装 但是无法找到这个管理后台。 而且我是用这个路由作为中继,那么这个路由的ip就会经常更换 尝试通过网上搜索引擎来…...
AI如何改变IT行业
AI如何改变IT行业 在当今数字化的社会中,人工智能(AI)不仅仅是一个技术词汇,而是一个正在重塑我们生活的现实时态。如果把AI比作一场即将到来的暴风雨,那么IT行业就是它的海洋。在这场风暴中,所有的船只都…...
运行vue项目,显示“npm”无法识别为 cmdlet、函数、脚本文件或可操作程序的名称
PS D:\weduproject\wedu1\wedu\wedu-fast-vue> npm run dev,运行时出现像下面这样的报红信息, npm : The term npm is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or …...

Kubernetes开发环境minikube | 开发部署apache tomcat web单节点应用
minikube是一个主要用于开发与测试Kubernetes应用的运行环境 本文主要描述在minikube运行环境中部署J2EE tomcat web应用 minikube start --force minikube status 如上所示,在Linux中启动minikube运行环境 service docker start docker version service docker …...
OpenCV相机标定与3D重建(44)初始化广角(鱼眼)相机的投影映射函数initWideAngleProjMap()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::initWideAngleProjMap 是 OpenCV 库中的一个函数,用于初始化广角(鱼眼)相机的投影映射。这个函数生成两个…...
现代前端框架
截至2025年,现代前端框架领域仍然以React、Vue和Angular等成熟框架为主导,同时一些新兴框架也在不断崛起和发展。以下是目前较为先进和受欢迎的前端框架: 成熟框架 React 由Facebook开发,是目前最流行的前端框架之一。它使用声明…...

Vue进阶(贰幺贰)npm run build多环境编译
文章目录 一、前言二、实施三、总结:需要打包区分不同环境四、拓展阅读 一、前言 项目开发阶段,会涉及打包部署到多个环境应用场景,在不同环境中,需要进行项目层面的区分,做不同的操作,可以利用打包的--mo…...

社交新零售下开源 AI 智能名片 2+1 链动模式 S2B2C 商城小程序的创新实践与发展剖析
摘要:在社交电商蓬勃发展并向社交新零售转型的浪潮中,多种创新模式与技术应用不断涌现。本文聚焦于开源 AI 智能名片 21 链动模式 S2B2C 商城小程序,深入探讨其在社交新零售格局下的内涵、优势、应用策略以及对行业发展的深远影响,…...

xml格式化(1):使用python的xml库实现自闭合标签
前言 最近一段时间一直想要写一个urdf格式化插件。 至于为什么嘛,因为使用sw2urdf插件,导出的urdf,同一标签的内容,是跨行的,这就导致,内容比较乱,而且行数比较多。影响阅读。 因此ÿ…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...

【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...