https://leetcode.com/problems/longest-palindromic-substring/
Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.
这道题有两种解法:
第一种是从每个字母出发往两边,直到找到palindromic的边界为止,注意,如果相邻两个字符相同的话,那么需要考虑两种情况,以其中一个字符为中心展开,和以这两个字符为中心展开。
这种解法时间复杂度O(n^2),空间复杂度O(1)
第二种是DP,本来我想用一维DP做的,代码如下:
public class Solution {
public String longestPalindrome(String s) {
if(s==null || s.length()==0) return "";
int max = 1;
int start = 0;
int end = 0;
int[] longest = new int[s.length()];
longest[0] = 1;
for(int i=1; i<s.length(); i++){
int j= i-longest[i-1]-1;
if(j<0 || s.charAt(j)!=s.charAt(i)){
longest[i] = 1;
int iter = i-1;
while(iter>=0 && s.charAt(iter)==s.charAt(i)){
longest[i]++;
iter--;
}
}
else{
longest[i] = longest[i-1]+2;
}
if(longest[i]>max){
max = longest[i];
start = i - longest[i]+1;
end = i;
}
}
return s.substring(start, end+1);
}
}
但过不了如“bananas”这种case, 返回回来的是“ana”,因为此时只能记录以字母i结尾的最长字符串,所以到第二个a的时候,记录的是"ana",但到第二个n的时候,应该是"nan",但由于前面记录的是"ana",所以它只会考虑“ana”前面的是否是"n",只会在前面一个字符的最长palindrome的基础上增加。
因此我们需要二维数组来记录任何[i, j]之间是否是palindrome
下面的解释来自:http://fisherlei.blogspot.com/2012/12/leetcode-longest-palindromic-substring.html
"
定义函数
P[i,j] = 字符串区间[i,j]是否为palindrome.
首先找个例子,比如S="abccb",
S= a b c c b
Index = 0 1 2 3 4
P[0,0] =1 //each char is a palindrome
P[0,1] =S[0] == S[1] , P[1,1] =1
P[0,2] = S[0] == S[2] && P[1,1], P[1,2] = S[1] == S[2] , P[2,2] = 1
P[0,3] = S[0] == S[3] && P[1,2], P[1,3] = S[1] == S[3] && P[2,2] , P[2,3] =S[2] ==S[3], P[3,3]=1
......................
由此就可以推导出规律
P[i,j] = 1 if i ==j
= S[i] ==S[j] if j = i+1
= S[i] == S[j] && P[i+1][j-1] if j>i+1
"
注意这里DP的执行顺序,例如"abcde", 判读"abcde"时,需要知道"bcd"是否对称,所以,代码中外层循环是以i为结束符,内层循环是以从0 - i 字符为开始字符 的字符串,这样就可以保证在执行DP时,需要的结果已经先算出来了。时间复杂度O(n^2),空间复杂度O(n^2)
public class Solution {
public String longestPalindrome(String s) {
if(s==null || s.length()==0) return "";
int max = 1;
int start = 0;
int end = 0;
boolean[][] valid = new boolean[s.length()][s.length()];
for(int i=0; i<s.length(); i++){
for(int j=0; j<=i; j++){
valid[j][i] = (s.charAt(i)==s.charAt(j) && (((i-j)<2) || valid[j+1][i-1]));
if(valid[j][i] && max < (i-j+1)){
max = i-j+1;
start = j;
end = i;
}
}
}
return s.substring(start, end+1);
}
}
下面还有一个O(n)的解法,用一位数组做的DP,不过没太看懂。。。。。有空再研究吧。。。。
http://articles.leetcode.com/2011/11/longest-palindromic-substring-part-ii.html
http://www.felix021.com/blog/read.php?2040
思路清晰真的太重要了,尤其是在设计DP算法的时候!