Leetcode 最长回文子串

目录

解法1:递归算法

解法2:Map取同字母位置法

解法3:中心扩展法

解法4:动态规划法

解法5: Manacher算法


示例 1:

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

示例 2:

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

提示:

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

解法1:递归算法

1)判断输入的字符串是否是回文,若是肯定为最大回文串。或者字符串长度<=1 直接返回。(结束条件)

2) 拆分问题降级。

若字符串不是回文,那么只能在s[0,n-2] 和 s[1,n-1]两个子串里去找最大回文串。

然后选取长度更大的那个返回结果即是结果。

方法很简单,代码如下:

class Solution {public String longestPalindrome(String s) {if (isPalindrome(s)) {return s;}String left, right;int n = s.length();// find palindrome in left partleft = longestPalindrome(s.substring(0, n-1));// find palindrome in right partright = longestPalindrome(s.substring(1, n));    if (left.length() > right.length()) {return left;} else {return right;}}public boolean isPalindrome(String s) {char[] schars = s.toCharArray();int n = schars.length;for (int i=0; i<n; i++) {if (schars[i] != schars[n-1-i]) {return false;}}return true;}
}

前面都能跑过,碰到测试用例:"babaddtattarrattatddetartrateedredividerb" 运行超时。

这个递归,很多重复计算,效率比较低。那就优化下,来个高效率点的吧。

解法2:Map取同字母位置法

我们知道每一个回文串,它的开头和结尾两个字母肯定相同。那么我们可以得到一个灵感,把所有字母的字符串中位置记录下来,回文只可能在那些出现了两次以上位置的字母里出现。

例如:"abcabcde"
Map [Character, List<Integer>]
 a => [0, 3] 
 b => [1, 4]
 c => [2, 5]
 d => [6]
 e => [7] 
那么我们从字母的位移列表中,选出超过2个的进行检查所有的字符串是否为回文,然后取出最大的就可以了。
 

代码如下:

class Solution {public String longestPalindrome(String s) {if (isPalindrome(s)) {return s;}// letter <-> count & index listMap<Character, List<Integer>> letterMap = new HashMap<>();char[] schars = s.toCharArray();for (int i=0; i<schars.length; i++) {Character c = Character.valueOf(schars[i]);List<Integer> indexs = letterMap.get(c);if (indexs != null) {indexs.add(Integer.valueOf(i));} else {indexs = new LinkedList<>();indexs.add(Integer.valueOf(i));letterMap.put(c, indexs);}}String maxRome = "" +schars[0];for (Map.Entry<Character,List<Integer>> entry: letterMap.entrySet()) {// more than one index position, maybe there is a palindromeList<Integer> indexList = entry.getValue();int indexSize = indexList.size();if (indexSize > 1) {for (int i=0; i<indexSize; i++) {for (int j=indexSize-1; j>i; j--) {int start = indexList.get(i);int end = indexList.get(j) + 1;// sub-string size is less than maxRome, skip itif (end-start <= maxRome.length()) {continue;} else {String subStr = s.substring(start,end);if (isPalindrome(subStr) && subStr.length() > maxRome.length()) {maxRome = subStr;}}}}}}return maxRome;}public boolean isPalindrome(String s) {int n = s.length();for (int i=0; i<n; i++) {if (s.charAt(i) != s.charAt(n-1-i)) {return false;}}return true;}}

运行效果:

虽然过了,但是5%的分布,效果不怎么样。稍微优化下。
1)代码中用的LinkedList来进行记录相同字母的位移下标,在频繁get的时候效率不如ArrayList高。
2)字母Map初始化的时候没有给定初始值,那么会导致resize占用时间。那么我们给定一个size*4/3作为它的初始值。

优化结果代码如下:
 

class Solution {public String longestPalindrome(String s) {char[] schars = s.toCharArray();if (isPalindrome(schars, 0, s.length()-1)) {return s;}// letter <-> count & index listMap<Character, List<Integer>> letterMap = new HashMap<>(s.length()*4/3);for (int i=0; i<schars.length; i++) {Character c = Character.valueOf(schars[i]);List<Integer> indexs = letterMap.get(c);if (indexs != null) {indexs.add(Integer.valueOf(i));} else {indexs = new ArrayList<>();indexs.add(Integer.valueOf(i));letterMap.put(c, indexs);}}String maxRome = "" +schars[0];for (Map.Entry<Character,List<Integer>> entry: letterMap.entrySet()) {// more than one index position, maybe there is a palindromeList<Integer> indexList = entry.getValue();int indexSize = indexList.size();if (indexSize > 1) {for (int i=0; i<indexSize; i++) {for (int j=indexSize-1; j>i; j--) {int start = indexList.get(i);int end = indexList.get(j);int subStrLen = end-start+1;// sub-string size is less than maxRome, skip itif (subStrLen <= maxRome.length()) {break;} else {String subStr = s.substring(start,end+1);if (isPalindrome(schars, start, end)) {maxRome = s.copyValueOf(schars, start, subStrLen);}}}}}}return maxRome;}public boolean isPalindrome(char[] chars, int start, int end) {while(start < end) {if (chars[start++] != chars[end--]) {return false;}}return true;}}

经过上面两个代码优化后,执行效果如下:

执行结果位于57%位置,还凑合吧。
 

解法3:中心扩展法

实现代码如下:
 

class Solution {public String longestPalindrome(String s) {int length = s.length();if (length < 2) {return s;}char[] schars = s.toCharArray();String maxRome = "" +schars[0];// search max palindrome from the middle point schars[i]// palindrome middle from (0, len-1]for (int i=1; i<length; i++) {// find max even palindrome from middle pointmaxRome = search(schars, i-1, i, maxRome);// find max odd palindrome from middle pointmaxRome = search(schars, i-1, i+1, maxRome);}return maxRome;}public String search(char[] schars, int left, int right, String maxRome) {int length = schars.length;while(left >= 0 && right<length && schars[left] == schars[right]) {left--;right++;}if (right - left -1 > maxRome.length()) {return String.copyValueOf(schars, left + 1, right - left -1);}return maxRome;}}

执行效果如下
93.2%分位,已经很好了。强烈推荐解法。 

解法4:动态规划法

理解起来稍微复杂点,可以作为学习动态规划算法的例子。

实现代码如下:
 

class Solution {public String longestPalindrome(String s) {int length = s.length();if (length < 2) {return s;}// palindrome[i][j] = true => s[i,j] is palindromeboolean[][] palindrome = new boolean[length][length];// len = 1, all is palindromefor (int i=0; i<length; i++) {palindrome[i][i] = true;}int start = 0, maxLen = 1;char[] schars = s.toCharArray();// palindrome[i][j] = palindrome[i+1][j-1] && s[i]==s[j]for (int len = 2; len<=length; len++) {for (int i=0; i<length; i++) {// j - i + 1 = lenint j = i + len -1;if (j>length-1) {break;}if (schars[i] == schars[j]) {if (len <= 3) {palindrome[i][j] = true;} else {palindrome[i][j] = palindrome[i+1][j-1];}} else {palindrome[i][j] = false;}if (palindrome[i][j] && len > maxLen) {start = i;maxLen = len;}}}return String.copyValueOf(schars, start, maxLen);}
}

运行效果如下:

19.07%还凑合吧。
 

解法5: Manacher算法

还有个Manacher算法比较复杂,效果也没见得比"中心扩展法"好太多,就不推荐了。

感兴趣的童鞋可以去这里看
. - 力扣(LeetCode)


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/886823.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot(8)-任务

目录 一、异步任务 二、定时任务 三、邮件任务 一、异步任务 使用场景&#xff1a;后端发送邮件需要时间&#xff0c;前端若响应不动会导致体验感不佳&#xff0c;一般会采用多线程的方式去处理这些任务&#xff0c;但每次都需要自己去手动编写多线程来实现 1、编写servic…

WebStorm 2022.3.2/IntelliJ IDEA 2024.3出现elementUI提示未知 HTML 标记、组件引用爆红等问题处理

WebStorm 2022.3.2/IntelliJ IDEA 2024.3出现elementUI提示未知 HTML 标记、组件引用爆红等问题处理 1. 标题识别elementUI组件爆红 这个原因是&#xff1a; 在官网说明里&#xff0c;才版本2024.1开始&#xff0c;默认启用的 Vue Language Server&#xff0c;但是在 Vue 2 项…

Odoo :免费且开源的农牧行业ERP管理系统

文 / 开源智造Odoo亚太金牌服务 引言 提供农牧企业数字化、智能化、无人化产品服务及全产业链高度协同的一体化解决方案&#xff0c;提升企业智慧种养、成本领先、产业互联的核心竞争力。 行业典型痛点 一、成本管理粗放&#xff0c;效率低、管控弱 产品研发过程缺少体系化…

【Unity踩坑】出现d3d11问题导致编辑器崩溃

升级到Unity 6&#xff0c;有时出现下面这种D3D11的问题&#xff0c;会导致编辑器崩溃。 有人总结了这个问题的解决方法&#xff0c;可以做为参考&#xff1a; Failed to present D3D11 swapchain due to device reset/removed. List of Solutions - Unity Engine - Unity Dis…

数据库基础(MySQL)

1. 数据库基础 1.1 什么是数据库 存储数据用文件就可以了&#xff0c;为什么还要弄个数据库? 文件保存数据有以下几个缺点&#xff1a; 文件的安全性问题文件不利于数据查询和管理文件不利于存储海量数据文件在程序中控制不方便 数据库存储介质&#xff1a; 磁盘内存 为…

JMeter监听器与压测监控之Grafana

Grafana 是一个开源的度量分析和可视化套件&#xff0c;通常用于监控和观察系统和应用的性能。本文将指导你如何在 Kali Linux 上使用 Docker 来部署 Grafana 性能监控平台。 前提条件 Kali Linux&#xff1a;确保你已经安装了 Kali Linux。Docker&#xff1a;确保你的系统已…

集群聊天服务器(13)redis环境安装和发布订阅命令

目录 环境安装订阅redis发布-订阅的客户端编程环境配置客户端编程 功能测试 环境安装 sudo apt-get install redis-server 先启动redis服务 /etc/init.d/redis-server start默认在6379端口上 redis是存键值对的&#xff0c;还可以存链表、数组等等复杂数据结构 而且数据是在…

linux常用指令总结(附Vim编辑器学习总结)

本文是博主对Linux中经常用到的一些指令进行的总结&#xff0c;文章也附带了Linux中经常用到的Vim编辑器的一些基本知识和使用指令&#xff0c;觉得有帮助的朋友可以点赞收藏&#xff01; 本文会持续进行更新 linux常用指令总结 $ pwd # 查看当前终端所在…

w046基于web的古典舞在线交流平台的设计与实现

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;原创团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文…

阿里云轻量应用服务器可以用在哪些场景呢

在数字化转型的浪潮中&#xff0c;中小企业面临着如何快速、高效地上云的挑战。阿里云轻量应用服务器&#xff08;SWAS&#xff09;作为一款专为中小企业设计的云服务产品&#xff0c;提供了简单易用、经济实惠的解决方案&#xff0c;助力企业轻松实现云端部署&#xff0c;赋能…

爬虫开发工具与环境搭建——使用Postman和浏览器开发者工具

第三节&#xff1a;使用Postman和浏览器开发者工具 在网络爬虫开发过程中&#xff0c;我们经常需要对HTTP请求进行测试、分析和调试。Postman和浏览器开发者工具&#xff08;特别是Network面板和Console面板&#xff09;是两种最常用的工具&#xff0c;能够帮助开发者有效地捕…

【操作系统】每日 3 题(二十九)

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4e3;专栏地址&#xff1a;https://blog.csdn.net/newin2020/category_12820365.html &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享操作系统面试中常见的面试题给大家~ ❤️…

JSON.stringify的应用说明

前言 JSON.stringify() 方法将 JavaScript 对象转换为字符串,在日常开发中较常用&#xff0c;但JSON.stringify其实有三个参数&#xff0c;后两个参数&#xff0c;使用较少&#xff0c;今天来介绍一下后两个参数的使用场景和示例。 语法及参数说明 JSON.stringify()&#xf…

Orcad 输出有链接属性的PDF

安装adobe pdf安装Ghostscript修改C:\Cadence\SPB_16.6\tools\capture\tclscripts\capUtils\capPdfUtil.tcl ​ 设置默认打印机为 Adobe PDF ​ 将Ghostscript的路径修改正确 打开cadence Orcad &#xff0c;accessories->candece Tcl/Tk Utilities-> Utilities->PD…

React(二)

文章目录 项目地址七、数据流7.1 子组件传递数据给父组件7.1.1 方式一:給父设置回调函数,传递给子7.1.2 方式二:直接将父的setState传递给子7.2 给props传递jsx7.2.1 方式一:直接传递组件给子类7.2.2 方式二:传递函数给子组件7.3 props类型验证7.4 props的多层传递7.5 cla…

Electron教程1-初学入门

玩转Electron Electron 是什么注意事项环境安装安装 vscode安装 git 第一个实例第二个实例第二个实例解读 总结问题解答 Electron 是什么 Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium 和 Node.js 到 二进制的 Electron 允许您保持一个…

类和对象——拷贝构造函数,赋值运算符重载(C++)

1.拷⻉构造函数 如果⼀个构造函数的第⼀个参数是自身类类型的引用&#xff0c;且任何额外的参数都有默认值&#xff0c;则此构造函数也叫做拷贝构造函数&#xff0c;也就是说拷贝构造是⼀个特殊的构造函数。 // 拷贝构造函数//d2(d1) Date(const Date& d) {_year d._yea…

一文详细深入总结服务器选型

1. 题记&#xff1a; 服务器选型工作是项目规划检讨的一项非常重要的工作&#xff0c;本文详细深入总结服务器选型。 2. 服务器基础知识概览 2.1 服务器的定义与功能 2.1 .1 定义 服务器是一种高性能计算机&#xff0c;其设计目的是在网络中提供服务。它可以处理来自多个客…

多线程--常见锁策略--Java

目录 一、悲观锁VS乐观锁 1.悲观锁 2.乐观锁 二、重量级锁VS轻量级锁 1.重量级锁 2.轻量级锁 三、自旋锁 1.自旋锁概念 四、公平锁VS非公平锁 1.公平锁 2.非公平锁 3.注意 五、可重入锁和不可重入锁 六、读写锁 1.线程对于数据的访问方式 注意&#xff1a;以下讲…

基于YOLOv8深度学习的医学影像阿尔兹海默症检测诊断系统研究与实现(PyQt5界面+数据集+训练代码)

阿尔茨海默症&#xff08;Alzheimer’s disease&#xff09;是一种常见的神经退行性疾病&#xff0c;主要表现为记忆丧失、认知能力下降以及行为和人格改变。随着全球老龄化问题的加剧&#xff0c;阿尔茨海默症的发病率也在逐年上升&#xff0c;给患者及其家庭带来了巨大的经济…