leetcode 5. 最长回文子串(Java版)
题目描述(题目难度,中等)
给定一个字符串 s
,找到 s
中最长的回文子串。你可以假设 s
的最大长度为 1000。
示例 1:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。
示例 2:
输入: “cbbd”
输出: “bb”
示例代码
时间复杂度为,空间复杂度为
class Solution {
public boolean isPalindrome(String s, int b, int e){//判断s[b...e]是否为回文字符串
int i = b, j = e;
while(i <= j){
if(s.charAt(i) != s.charAt(j)) return false;
++i;
--j;
}
return true;
}
public String longestPalindrome(String s) {
if(s.length() <=1){
return s;
}
int l = 1, j = 0, ll = 1;
for(int i = 1; i < s.length(); ++i){
//下面这个if语句就是用来维持循环不变式,即ll恒表示:以第i个字符为尾的最长回文子串的长度
if(i - 1 - ll >= 0 && s.charAt(i) == s.charAt(i-1-ll)) ll += 2;
else{
while(true){//重新确定以i为边界,最长的回文字串长度。确认范围为从ll+1到1
if(ll == 0||isPalindrome(s,i-ll,i)){
++ll;
break;
}
--ll;
}
}
if(ll > l){//更新最长回文子串信息
l = ll;
j = i;
}
}
return s.substring(j-l+1, j+1);//返回从j-l+1到j长度为l的子串
}
}
思路解析
这是一道老题目了,本来想自己想出一个的解法出来。想了半天,很兴奋的觉得想到了一个的解法,结果拿去一运行,输出不正确,最后发现是因为自己的想法在细节上存在漏洞。其实整体的思路还是没问题的,上面的代码就是按原来的想法改的,修补了细节,不过时间复杂度变为了。
下面描述一下上面代码的思路:
假设输入的字符串为 S ,首先我借助两个变量来保存最长回文字串的信息,分别为 l 和 j。其中 l 表示最长回文子串的长度,j 表示最长回文子串的尾字符在 S 中的下标。这样最后算法结束后,便可通过 l 和 j 定位到最长回文子串,并返回算法结果。另外还使用变量 ll 表示以当前字符为边界的最长回文子串的长度。
算法的具体流程如下:
如果当前遍历到 S 的第 i(从0开始)个字符(此时的 l 和 j 保存的是 S[0…i-1]的最长回文子串的信息),通过第 i-1 个字符的 ll 来判断当前字符有没有增加前一个最长回文子串的长度,如果增加了,则 ll 自增 2,此时更新后的 ll 代表的就是以第 i 个字符为边界的最长回文子串的长度。如果没有增加,就需要重新确定以第 i 个字符为边界的最长回文子串的长度,确认范围为从 ll+1 到 1。
ll 更新后,比较 ll 与 l 的大小,如果 ll 变得比 l 要大,则将当前 ll 的值赋给 l,i 的值赋给 j。
上述流程的核心是,一定要在遍历的时候保证 ll 表示的一定是以当前字符为尾的最长回文子串的长度,这一点即本算法的循环不变式。遵循该循环不变式,遍历一遍 S 后即可得到结果。
最后提一下,最长回文子串问题是有 O(n) 时间复杂度的算法的,算法名字叫 Manacher 算法,又叫 “马拉车”算法,感兴趣的同学可以去搜索了解一下。
- Pwnable.tw刷题之Silverbullet破解过程分享
- 鸡肋CSRF和Self-XSS组合的变废为宝
- 简易--go语言redis连接池
- Golang中channel使用的一些小技巧
- Go语言的管道Channel用法实例
- 【数据库】MySQL进阶二、索引简易教程
- 【数据库】MySQL进阶六、模糊查询用法
- 【选择题】Java基础测试九(16道)
- 用Ansible自动供应vmware虚拟机--构建数据中心一体化运维平台第二篇
- 【编程题】Java编程题五(10道)
- 如何有效地对Docker的镜像进行管理?
- go语言的多核并行化例子
- 【选择题】Java基础测试二(15道)
- App与后台通信:从文本协议到二进制协议
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- 数据结构之树
- UNIX网络编程卷1(第三版)套接字编程简介
- UNIX网络编程卷1(第三版)readn,writen和readline函数
- UNIX网络编程卷1(第三版)基本TCP套接字编程
- Ubuntu下linux映射共享盘到window下方法
- 数据同步写入磁盘:sync
- 惯用的关机命令:shutdown
- 重启、关机:reboot,halt,poweroff
- 使用Docker构建ZooKeeper镜像
- Linux进程间的通信
- 如何使用jMeter对需要CSRF token验证的OData服务进行并发性能测试
- 如何让SAP C4C自定义BO实现附件上传的功能
- SAP C4C基于自定义BO开发的OWL UI,如何实现动态访问控制
- 使用ABAP CL_HTTP_CLIENT类消费OData服务时,如何避免CSRF令牌验证失败错误
- 使用ABAP代码消费SAP Cloud for Customer的OData服务