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的更多相关文章

  1. 【LeetCode】005. Longest Palindromic Substring

    Given a string s, find the longest palindromic substring in s. You may assume that the maximum lengt ...

  2. 【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 ...

  3. 【一天一道LeetCode】#5 Longest Palindromic Substring

    一天一道LeetCode系列 (一)题目 Given a string S, find the longest palindromic substring in S. You may assume t ...

  4. 【LeetCode OJ】Longest Palindromic Substring

    题目链接:https://leetcode.com/problems/longest-palindromic-substring/ 题目:Given a string S, find the long ...

  5. 005 Longest Palindromic Substring 最长回文子串

    Given a string s, find the longest palindromic substring in s. You may assume that the maximum lengt ...

  6. LeetCode(3)题解: Longest Palindromic Substring

    https://leetcode.com/problems/longest-palindromic-substring/ 题目: Given a string S, find the longest ...

  7. 【LeetCode】5. Longest Palindromic Substring 最长回文子串

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 公众号:负雪明烛 本文关键词:最长回文子串,题解,leetcode, 力扣,python ...

  8. 【LeetCode】5. Longest Palindromic Substring 最大回文子串

    题目: Given a string S, find the longest palindromic substring in S. You may assume that the maximum l ...

  9. No.005 Longest Palindromic Substring

    5. Longest Palindromic Substring Total Accepted: 120226 Total Submissions: 509522 Difficulty: Medium ...

  10. 【leetcode】5. Longest Palindromic Substring

    题目描述: Given a string S, find the longest palindromic substring in S. You may assume that the maximum ...

随机推荐

  1. 查看oracle的执行计划

    基于ORACLE的应用系统很多性能问题,是由应用系统SQL性能低劣引起的,所以,SQL的性能优化很重要,分析与优化SQL的性能我们一般通过查看该SQL的执行计划,本文就如何看懂执行计划,以及如何通过分 ...

  2. linux用户和组管理,/etc/passwd 、/etc/shadow和/etc/group --学习

    一./etc/passwd 和/etc/shadow解释 与用户相关的系统配置文件主要有/etc/passwd 和/etc/shadow,其中/etc/shadow是用户资讯的加密文件,比如用户的密码 ...

  3. swift 需求: 导航栏和HeaderView 使用一个背景图片。

    问题界面 需求: 导航栏和HeaderView 使用一个背景图片.解决方案: 让 导航栏 变成透明. override func viewWillAppear(_ animated: Bool) { ...

  4. js学习(4) 函数

    JavaScript有三种声明函数的方法 (1)function命令 function print(s) { console.log(s); } (2)函数表达式 1.var print = func ...

  5. 48- java Arrays.sort和collections.sort()再次总结

    今天又碰到一个新BUG,记下来. 一直报空指针异常,我就很奇怪了,怎么就空指针了呢,我输出时,也能输出东西呀. 原来Arrays.sort() 和 Collections.sort() 都是对整个数组 ...

  6. 如何学好游戏3D引擎编程

    注:本文是网上看到的一篇文章,感觉写的很好,因此收藏了下来 <如何学好游戏3D引擎编程>此篇文章献给那些为了游戏编程不怕困难的热血青年,它的神秘要我永远不间断的去挑战自我,超越自我,这样才 ...

  7. 51nod 1344

    一个很简单的算法题,求最小的前缀和,就是要注意数据范围要开一个longlong #include<iostream> using namespace std; int main() { i ...

  8. JSP :使用<%@include%>报Duplicate local variable path 错误

    今天在做商城页面,遇到问题: <%@include file="menu.jsp" %> 错误提示: Multiple annotations found at thi ...

  9. canvas画圆环

    <!DOCTYPE html><html> <head> <title> </title> <meta http-equiv=&quo ...

  10. javascript常见内存泄露

    一.全局变量引起的内存泄漏 function func(){ lmw = 123456 //lmw是全局变量,不会被释放 } 二.闭包引起的内存泄漏 function func(){ var lmw ...