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条件直接就退出了。
No.005 Longest Palindromic Substring的更多相关文章
- 【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--No.005 Longest Palindromic Substring
5. Longest Palindromic Substring Total Accepted: 120226 Total Submissions: 509522 Difficulty: Medium ...
- 【LeetCode】005. Longest Palindromic Substring
Given a string s, find the longest palindromic substring in s. You may assume that the maximum lengt ...
- 005 Longest Palindromic Substring 最长回文子串
Given a string s, find the longest palindromic substring in s. You may assume that the maximum lengt ...
- [Leetcode]005. Longest Palindromic Substring
public String longestPalindrome(String s) { int start = 0, end = 0; for (int i = 0; i < s.length( ...
- No.005:Longest Palindromic Substring
问题: Given a string S, find the longest palindromic substring in S. You may assume that the maximum l ...
- 最长回文子串-LeetCode 5 Longest Palindromic Substring
题目描述 Given a string S, find the longest palindromic substring in S. You may assume that the maximum ...
- leetcode--5. Longest Palindromic Substring
题目来自 https://leetcode.com/problems/longest-palindromic-substring/ 题目:Given a string S, find the long ...
- [LeetCode] Longest Palindromic Substring 最长回文串
Given a string S, find the longest palindromic substring in S. You may assume that the maximum lengt ...
随机推荐
- SqlServer——阻止保存要求重新创建表的更改
场景: 修改已有数据的列宽时,提示“阻止保存要求重新创建表的更改”. 解决: 工具-〉选项-〉左侧有个 设计器-〉表设计器和数据库设计器 -> 阻止保存要求重新创建表的更改(右侧) 把钩去掉即可 ...
- 228. Summary Ranges
Given a sorted integer array without duplicates, return the summary of its ranges. For example, give ...
- linux下mongodb定时备份指定的集合
目标:把一台linux机上mongodb的数据定时备份到另一台机上: 过程: 一开始打算使用mongoexport和mongoimport,但是总是会报“\x00”字符串不能识别的问题,后来就改成了m ...
- 删除SQL server 实例
在网上找到下面几种方法,本人使用的是第一种,很实用. 1.删除 SQL Server 的特定实例若要删除 SQL Server 的某个特定实例,请按照以下步骤操作: 找到并删除%drive%:\\Pr ...
- Java执行main方法,异常为:could not find the main class.program will exit
未解决. Java执行方法,异常为:could not find the main class.program will exitmain 原文地址:http://rogerfederer.iteye ...
- SpringAOP所支持的AspectJ切点指示器
在spring中尝试使用AspectJ其他指示器时,将会抛出IllegalArgumentException异常. 当我们查看上面展示的这些spring支持的指示器时,注意只有execution指示器 ...
- NeHe OpenGL教程 第九课:移动图像
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- 发布在IIS上的Web程序,调用服务器的COM组件
场景大致是这样的,在工厂中分布着许多的PDA点,这些PDA点都要进行实时的扫描--打印操作.实现方法是采用网络打印机,然后服务器安装驱动,管理着所有的打印机.然后服务器,发布一个WebService, ...
- 转--Android:TextView属性大全
android:autoLink 设置是否当文本为URL链接/email/电话号码/map时,文本显示为可点击的链接.可选值(none/web/email/phone/map/all) android ...
- 专注于提高“人肉测试”效率,Bugtags已完成600万元天使轮融资
导语:近日,专注于移动测试的缺陷发现及管理工具“Bugtags”创始人张磊独家透露,Bugtags已完成600万元天使轮投资,投资方为高捷资本. 近日,专注于移动测试的缺陷发现及管理工具“Bugtag ...