LeetCode5.最长回文子串

 昨天和之前打比赛的队友聊天,他说他面百度面到这道算法题,然后他用暴力法解的,面试官让他优化他没优化出来,这道题我之前没写过,我就想看看我能不能用效率高一点的方法把它做出来,我一开始就在想用递归或者翻转字符串等等技巧,想了半个多小时都想不到,然后算了,我也用暴力法吧,然后就写了如下代码:

class Solution {public String longestPalindrome(String s) {int n = s.length();String ans = "";for(int i = 0;i<n;i++){int l = i, r=i;while(l<= r && l >=0 && r < n && s.charAt(l) == s.charAt(r)){String tem =s.substring(l,r+1);if(r-l+1 > ans.length())ans=tem;l--;r++;}l = i;r=l+1;while(l >=0 && r < n && s.charAt(l) == s.charAt(r)){String tem =s.substring(l,r+1);if(r-l+1 > ans.length())ans=tem;l--;r++;}}return ans;}}

这个暴力法就非常简单了,就是遍历字符的每个字符,然后以这个字符为中心用左右指针往两边移动,然后是写了两个while,一个是左右指针指向同一个字符然后向左右移动,还有一个是左右指针指向相邻的字符向两边移动。

还是看看官方题解的做法吧。

题解的方法一是用的动态规划:

class Solution {public String longestPalindrome(String s) {int len = s.length();if(len < 2)return s;boolean[][] dp = new boolean[len][len];for(int i=0;i<len;i++){dp[i][i] = true;}int begin =0;int maxLen =1;char[] str = s.toCharArray();for(int L =2;L<=len;L++){for(int i=0;i<len;i++){int j = i+L-1;if(j>=len){break;}else{if(str[i] != str[j]){dp[i][j] = false;}else{if(j-i<3){dp[i][j] = true;}else{dp[i][j] = dp[i+1][j-1];}}}if(dp[i][j] && j-i+1 > maxLen){maxLen = j-i+1;begin = i;}}}return s.substring(begin, begin+maxLen);}}

dp[i][j]表示s的第i个字符到第j个字符这一个子串是不是一个回文字符串。

首先,初始状态:dp[i][i] = true;

然后,状态转移方程:dp[i][j] = ?

第一种情况,s.charAt(i) != s.charAt(j), 那么dp[i][j] = false;

第二种情况,s.charAt(i) == s.charAt(j),如果子串长度小于3,那么dp[i][j]=true;否则dp[i][j] = dp[i-1][j+1]

只要找出dp[i][j]中为true且长度最大的那个就行,这一步在填充dp的数组的同时进行,不用另外遍历,只要一个max动态更新就行。然后值得注意的是这里是把字符串转成了字符数组,因为我们需要频繁的找字符串中的字符,用数组效率更高,用charAt方法需要遍历字符串,而数组可以直接通过寻址公式得出。

题解的第二种方法用的是中心扩展,和我的方法差不多,只是它把while循环封装成了函数而已,以下是题解方法二代码:

class Solution {public String longestPalindrome(String s) {if (s == null || s.length() < 1) {return "";}int start = 0, end = 0;for (int i = 0; i < s.length(); i++) {int len1 = expandAroundCenter(s, i, i);int len2 = expandAroundCenter(s, i, i + 1);int len = Math.max(len1, len2);if (len > end - start) {start = i - (len - 1) / 2;end = i + len / 2;}}return s.substring(start, end + 1);}public int expandAroundCenter(String s, int left, int right) {while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {--left;++right;}return right - left - 1;}
}

题解的方法三就比较高级了,时间复杂度只有O(n),叫Manacher算法:

定义一个概念”臂长“,如果一个回文字符串的长度是2*lenght+1,那么这个回文字符串的臂长就是length。

如果位置j的臂长为length那么如何找到位置i的臂长呢?

对于奇数长度的回文字符串而言:

如果i关于j的对称点2*j-i的臂长是n,那么位置i的臂长是min(n,2*j-i)。这个其实很好理解,因为j左右length拿一段是对称的,所以如果2*j-i有n的臂长按道理i也是这么大的臂长,但是只有length这一部分是对称的,而2*j-i的对称部分还可以向两边扩展,所以i的臂长只能取n和2*j-i的最小值。

偶数长度的回文字符串呢?

我们通过在字符串的两头和没两个字符之间加上#,这样无论奇数还是偶数长度的回文字符串都变成了奇数长度的回文字符串,比如aaba处理成#a#a#b#a#,偶数长度的回文字符串aa变成了#a#a#。aba还是变成奇数#a#b#a#。需要注意的是这里添加的#需要是字符串里面没有出现过的。最后记得把回文字符还原,把#去掉。以下是Manacher方法的代码:

class Solution {public String longestPalindrome(String s) {int start = 0, end = -1;StringBuffer t = new StringBuffer("#");for (int i = 0; i < s.length(); ++i) {t.append(s.charAt(i));t.append('#');}t.append('#');s = t.toString();List<Integer> arm_len = new ArrayList<Integer>();int right = -1, j = -1;for (int i = 0; i < s.length(); ++i) {int cur_arm_len;if (right >= i) {int i_sym = j * 2 - i;int min_arm_len = Math.min(arm_len.get(i_sym), right - i);cur_arm_len = expand(s, i - min_arm_len, i + min_arm_len);} else {cur_arm_len = expand(s, i, i);}arm_len.add(cur_arm_len);if (i + cur_arm_len > right) {j = i;right = i + cur_arm_len;}if (cur_arm_len * 2 + 1 > end - start) {start = i - cur_arm_len;end = i + cur_arm_len;}}StringBuffer ans = new StringBuffer();for (int i = start; i <= end; ++i) {if (s.charAt(i) != '#') {ans.append(s.charAt(i));}}return ans.toString();}public int expand(String s, int left, int right) {while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {--left;++right;}return (right - left - 2) / 2;}
}

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

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

相关文章

使用dockerfile 构建自己的nacos-mysql

前言 在部署nacos的时候触发的脑袋灵光一闪&#xff0c;每次部署nacos都要部署下mysql服务器&#xff0c;然后导入sql语句&#xff0c;配置nacos配置文件&#xff0c;那有没有简单的方法实现一键部署nacos和nacos-mysql 呢? 答案是肯定&#xff01;如下目录图&#xff1a; …

C++笔记之Delegate和委托构造(Delegating constructor)

C笔记之Delegate和委托构造辨析 code review! —— 杭州 2023-12-10 文章目录 C笔记之Delegate和委托构造辨析0.有道词典&#xff1a;英语发音1.ChatGPT&#xff1a;delegate概念详解2.Delegate和“将可调用对象作为函数参数”是不是一回事&#xff1f;3.C的Delegate示例4.…

二维码智慧门牌管理系统升级解决方案:数字化房产管理

文章目录 前言一、全面信息记录&#xff1a;提升管理效率二、多种优势功能&#xff1a;系统化管理与无缝对接三、安全隐私保护&#xff1a;数据安全的重要性四、总结&#xff1a;提升管理效率与居住体验 前言 科技驱动房产管理 随着科技的飞速发展&#xff0c;房产管理领域也面…

力扣每日一题day33[111. 二叉树的最小深度]

给定一个二叉树&#xff0c;找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明&#xff1a;叶子节点是指没有子节点的节点。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;2示例 2&#xff1a; 输入…

Day56力扣打卡

打卡记录 数对统计&#xff08;DP状态压缩&#xff09; 参考文献 #include <bits/stdc.h>using namespace std;void solve(){int n;cin >> n;map<int, int> mapp;vector<int> a(n);for (auto& x : a){cin >> x;mapp[x] ;}vector<array&…

探索HarmonyOS_开发软件安装

随着华为推出HarmonyOS NEXT 宣布将要全面启用鸿蒙原声应用&#xff0c;不在兼容安卓应用&#xff0c; 现在开始探索鸿蒙原生应用的开发。 HarmonyOS应用开发官网 - 华为HarmonyOS打造全场景新服务 鸿蒙官网 开发软件肯定要从这里下载 第一个为微软系统(windows)&#xff0c;第…

深度学习 | Pytorch深度学习实践 (Chapter 12 Basic RNN)

十二、Basic RNN —— 实际上就是对线性层的复用 使用RNN最重要的两点&#xff1a; 了解序列数据的维度&#xff1b;循环过程所用的权重共享机制&#xff1b; 一般就是自己写个循环&#xff0c;权重层重复用就行了&#xff1b; 回顾&#xff1a;-----------------------------…

Spring Cloud gateway - CircuitBreaker GatewayFilte

前面学习Spring cloud gateway的时候&#xff0c;做测试的过程中我们发现&#xff0c;Spring Cloud Gateway不需要做多少配置就可以使用Spring Cloud LoadBalance的功能&#xff0c;比如&#xff1a; spring:application:name: spring-gatewaycloud:gateway:routes:- id: path…

DSP外部中断笔记

中断原理 三部分 注意 &#xff0c;外部中断使能&#xff0c;PIE使能&#xff0c;CPU中断使能 外部中断有7个&#xff0c;PIE有12组&#xff0c;一个组有8个中断复用。只有一个CPU中断可执行。 外部中断原理 1、外部中断概述 外部中断结构图 外部中断XINT1对应的是0到31GPIO…

C/C++常见面试题(二)

接前面C/C常见面试题&#xff08;一&#xff09;&#xff0c;继续巩固 目录 1 sizeof和strlen的区别 2 宏定义的陷进 3 不使用sizeof计算出类型或者变量所占的内存的字节数 4 给定一个数判断是否其是2的N次幂 5 C/C打印所在文件、行号、函数、日期&#xff0c;时间、遵循的…

Android P 9.0 增加以太网静态IP功能

效果图 一、Settings添加以太网的配置&#xff1a; 1、vendor\mediatek\proprietary\packages\apps\MtkSettings\res\xml\network_and_internet.xml <com.android.settingslib.RestrictedPreferenceandroid:key"ethernet_settings"android:title"string/et…

TailwindCSS 配置可视化检查器

问题 TailwindCSS 框架为我们提供了大量默认的类和属性&#xff0c;而且开发者也能够自定义类和配置。 对于初学者来说&#xff0c;这些配置其实是比较复杂的&#xff0c;这也是tailwindcss最大的入手成本&#xff0c;开发者的记忆负担和心智负担也都比较大。 有没有办法能够…