LeetCode--No.005 Longest Palindromic Substring
5. Longest Palindromic Substring
- Total Accepted: 120226
- Total Submissions: 509522
- Difficulty: Medium
Given a string s, find the longest palindromic(回文) substring in sS. You may assume that the maximum length of s is 1000, and there exists one unique longest palindromic substring.
推荐解法3,直观,有效,好理解
方法一:暴力搜索(O(N³))
这个思路就很简单了,就是直接求出每一个子串,然后判断其是否为回文。我们从子串长度最长开始,依次递减,如果遇到是回文的,则直接返回即可。循环结束如果没有回文,则返回null。
值得注意的一点是因为题目直接说了肯定存在回文,并且最大长度的回文唯一,所以在当字符串长度大于1的时候,最大回文长度必定大于1(如果为1的话,则每一个单独字符都可以作为最长长度的回文),所以搜索长度递减到2就结束了。题目中肯定存在大于2的回文,所以不会直到最后循环结束返回null这一步,所以最后直接写的返回null无关紧要。
/*
* 方法一:暴力搜索
*/
public String longestPalindrome(String s) {
if (s == null || s.length() == 0 || s.length() == 1) {
return s;
} String sub;
for (int subLen = s.length(); subLen > 1; subLen--) {
for (int startIndex = 0; startIndex <= (s.length() - subLen); startIndex++) {
// 列出所有子串,然后判断子串是否满足有重复
if (startIndex != (s.length() - subLen)) {
sub = s.substring(startIndex, startIndex + subLen);
} else {
sub = s.substring(startIndex);
}
System.out.println(sub);
if (isPalindrome(sub)) {
return sub;
}
}
} return null ;
} private boolean isPalindrome(String sub) {
for(int i = 0 ; i <= sub.length()/2 ; i++){
if(sub.charAt(i) != sub.charAt(sub.length()-i-1)){
return false ;
}
}
return true ;
}
方法二:动态规划O(N²)
更简洁的做法,使用动态规划,这样可以把时间复杂度降到O(N²),空间复杂度也为O(N²)。做法如下:
首先,写出动态转移方程。
Define P[ i, j ] ← true iff the substring Si … Sj is a palindrome, otherwise false.
P[ i, j ] ← ( P[ i+1, j-1 ] and Si = Sj ) ,显然,如果一个子串是回文串,并且如果从它的左右两侧分别向外扩展的一位也相等,那么这个子串就可以从左右两侧分别向外扩展一位。
其中的base case是
P[ i, i ] ← true
P[ i, i+1 ] ← ( Si = Si+1 )
然后,看一个例子。
假设有个字符串是adade,现在要找到其中的最长回文子串。使用上面的动态转移方程,有如下的过程:
按照红箭头->黄箭头->蓝箭头->绿箭头->橙箭头的顺序依次填入矩阵,通过这个矩阵记录从i到j是否是一个回文串。
/*
* 方法二:动态规划的方法
*/
public String longestPalindrome2(String s) {
if (s == null || s.length() == 0 || s.length() == 1) {
return s;
}
char [] arr = s.toCharArray() ;
int len = s.length() ;
int startIndex = 0 ;
int endIndex = 0 ;
boolean [][] dp = new boolean [len][len] ;
dp[0][0] = true ;
for(int i = 1 ; i < len ; i++){
//dp[i][i]置为true
dp[i][i] = true ;
//dp[i-1][i]判断true或false
if(arr[i-1] != arr[i]){
dp[i-1][i] = false ;
}else{
dp[i-1][i] = true ;
startIndex = i-1 ;
endIndex = i ;
}
}
//填充其他地方的值
for(int l = 2 ; l < len ; l++){
for(int i = 0 ; i < len-l ; i++){
int j = i+l ;
if(dp[i+1][j-1] && (arr[i] == arr[j])){
dp[i][j] = true ;
if((j-i) > (endIndex - startIndex)){
startIndex = i ;
endIndex = j ;
}
}
}
}
//返回最长回文字符串
if(endIndex == (len-1)){
return s.substring(startIndex) ;
}else{
return s.substring(startIndex, endIndex+1) ;
}
}
下面的方法参考自 http://blog.csdn.net/feliciafay/article/details/16984031
方法三:从中间向两边展开O(N²)(比动态规划方法好理解)
回文字符串显然有个特征是沿着中心那个字符轴对称。比如aha沿着中间的h轴对称,a沿着中间的a轴对称。那么aa呢?沿着中间的空字符''轴对称。所以对于长度为奇数的回文字符串,它沿着中心字符轴对称,对于长度为偶数的回文字符串,它沿着中心的空字符轴对称。对于长度为N的候选字符串,我们需要在每一个可能的中心点进行检测以判断是否构成回文字符串,这样的中心点一共有2N-1个(2N-1=N-1 + N)。检测的具体办法是,从中心开始向两端展开,观察两端的字符是否相同。代码如下:
//从中间向两边展开
string expandAroundCenter(string s, int c1, int c2) {
int l = c1, r = c2;
int n = s.length();
while (l >= && r <= n- && s[l] == s[r]) {
l--;
r++;
}
return s.substr(l+, r-l-);
} string longestPalindromeSimple(string s) {
int n = s.length();
if (n == ) return "";
string longest = s.substr(, ); // a single char itself is a palindrome
for (int i = ; i < n-; i++) {
string p1 = expandAroundCenter(s, i, i); //长度为奇数的候选回文字符串
if (p1.length() > longest.length())
longest = p1; string p2 = expandAroundCenter(s, i, i+);//长度为偶数的候选回文字符串
if (p2.length() > longest.length())
longest = p2;
}
return longest;
}
四、 时间复杂度为O(N)的算法
在这里看到了更更简洁的做法,可以把时间复杂度降到O(N).具体做法原文说得很清楚,有图有例,可以仔细读读。这里我只想写写,为什么这个算法的时间复杂度是O(N)而不是O(N²)。从代码中看,for循环中还有个while,在2层嵌套的循环中,似乎应该是O(N²)的时间复杂度。
// Transform S into T.
// For example, S = "abba", T = "^#a#b#b#a#$".
// ^ and $ signs are sentinels appended to each end to avoid bounds checking
string preProcess(string s) {
int n = s.length();
if (n == ) return "^$";
string ret = "^";
for (int i = ; i < n; i++)
ret += "#" + s.substr(i, ); ret += "#$";
return ret;
} string longestPalindrome(string s) {
string T = preProcess(s);
int n = T.length();
int *P = new int[n];
int C = , R = ;
for (int i = ; i < n-; i++) {
int i_mirror = *C-i; // equals to i' = C - (i-C) P[i] = (R > i) ? min(R-i, P[i_mirror]) : ; // Attempt to expand palindrome centered at i
while (T[i + + P[i]] == T[i - - P[i]])
P[i]++; // If palindrome centered at i expand past R,
// adjust center based on expanded palindrome.
if (i + P[i] > R) {
C = i;
R = i + P[i];
}
} // Find the maximum element in P.
int maxLen = ;
int centerIndex = ;
for (int i = ; i < n-; i++) {
if (P[i] > maxLen) {
maxLen = P[i];
centerIndex = i;
}
}
delete[] P; return s.substr((centerIndex - - maxLen)/, maxLen);
}
时间复杂度为什么是O(N)而不是O(N²)呢?
假设真的是O(N²),那么在每次外层的for循环进行的时候(一共n步),对于for的每一步,内层的while循环要进行O(N)次。而这是不可能。因为p[i]和R是有相互影响的。while要么就只走一步,就到了退出条件了。要么就走很多很步。如果while走了很多步,多到一定程度,会更新R的值,使得R的值增大。而一旦R变大了,下一次进行for循环的时候,while条件直接就退出了。
LeetCode--No.005 Longest Palindromic Substring的更多相关文章
- 【LeetCode】005. Longest Palindromic Substring
Given a string s, find the longest palindromic substring in s. You may assume that the maximum lengt ...
- 【JAVA、C++】LeetCode 005 Longest Palindromic Substring
Given a string S, find the longest palindromic substring in S. You may assume that the maximum lengt ...
- 【一天一道LeetCode】#5 Longest Palindromic Substring
一天一道LeetCode系列 (一)题目 Given a string S, find the longest palindromic substring in S. You may assume t ...
- 【LeetCode OJ】Longest Palindromic Substring
题目链接:https://leetcode.com/problems/longest-palindromic-substring/ 题目:Given a string S, find the long ...
- 005 Longest Palindromic Substring 最长回文子串
Given a string s, find the longest palindromic substring in s. You may assume that the maximum lengt ...
- LeetCode(3)题解: Longest Palindromic Substring
https://leetcode.com/problems/longest-palindromic-substring/ 题目: Given a string S, find the longest ...
- 【LeetCode】5. Longest Palindromic Substring 最长回文子串
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 公众号:负雪明烛 本文关键词:最长回文子串,题解,leetcode, 力扣,python ...
- 【LeetCode】5. Longest Palindromic Substring 最大回文子串
题目: Given a string S, find the longest palindromic substring in S. You may assume that the maximum l ...
- No.005 Longest Palindromic Substring
5. Longest Palindromic Substring Total Accepted: 120226 Total Submissions: 509522 Difficulty: Medium ...
- 【leetcode】5. Longest Palindromic Substring
题目描述: Given a string S, find the longest palindromic substring in S. You may assume that the maximum ...
随机推荐
- 微信小程序 验证码倒计时组件
https://blog.csdn.net/susuzhe123/article/details/80032224
- mysql_day03
MySQL-Day02回顾1.表记录的管理 1.删除表记录 1.delete from 表名 where 条件; ## 不加where条件全部删除 2.更新表记录 1.update 表名 set 字段 ...
- 使用ibatis时 sql中 in 的参数赋值(转)
转:http://www.cnblogs.com/sunzhenchao/archive/2012/12/03/2799365.html 一.问题描述: 1.在使用ibatis执行下面的sql: up ...
- Django的rest_framework认证组件之局部设置源码解析
前言: Django的rest_framework组件的功能很强大,今天来我来给大家剖析一下认证组件 下面进入正文分析,我们从视图开始,一步一步来剖析认证组件 1.进入urls文件 url(r'^lo ...
- react项目的ant-design-mobile的使用
现在测试一下ant-design-mobile的使用,引用一个Button 没有样式 这个问题是没有引入样式 解决方法有两种 这种方法自己弄不出来,然后用另外一种方法 引入样式: import 'an ...
- [leetcode]31. Next Permutation下一个排列
Implement next permutation, which rearranges numbers into the lexicographically next greater permuta ...
- Java日志框架-logback的介绍及配置使用方法(纯Java工程)(转)
说明:内容估计有些旧,2011年的,但是大体意思应该没多大变化,最新的配置可以参考官方文档. 一.logback的介绍 Logback是由log4j创始人设计的又一个开源日志组件.logback当前分 ...
- 【Spring】浅谈spring为什么推荐使用构造器注入
一.前言 Spring框架对Java开发的重要性不言而喻,其核心特性就是IOC(Inversion of Control, 控制反转)和AOP,平时使用最多的就是其中的IOC,我们通过将组件交由S ...
- Robotics Tools
https://sites.google.com/site/sunglok/rv_tool/robot Robotics Tools Contents 1 Robotics Tutorials 2 R ...
- osg探究补充:osg数据加载原理(插件机制简介)
前言 我们接着昨天的继续,昨天主要是讲解了DatabasePager类中的特定的成员变量以及run函数的第一部分,对所要请求加载的数据按照是否是网络数据进行分类加载模式.今天我们就看看数据是怎们加载到 ...