5. 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.
Example:
Input: "babad" Output: "bab" Note: "aba" is also a valid answer.
Example:
Input: "cbbd" Output: "bb"
1 . 我的思路:找出 s 和 s的翻转字符串的最长的共同子串,即为其最长回文字符串。方法就是以 s 为基准,将其翻转字符串分别左移 和 右移 0-n-1,然后找出其中最长的连续子串即可,但是还要考虑这种情况
"abcdasdfghjkldcba"
所以在更新最长子串的时候要比较其索引排除上面那种情况,最终时间复杂度为O(n3)。
const int maxlen = 1005;
int last_st,st,Max,cnt,mark,p = -1;
int judge(char* s,int st,int Max){
for(int i = st,j = Max - 1;i < Max;i++,j--){
if(s[i] != s[j]) return 0;
}
return 1;
}
void findMaxlen(int i,int j,int k,char* s){
if(mark && s[i] == s[j]){
if(cnt > Max && judge(s,st,)){
Max = cnt;
last_st = st;
}
cnt = 1;
st = i;
mark = 0;
}
else if(s[i] == s[j]) cnt++;
else mark = 1;
if(i - j == p - k){
if(cnt > Max){
Max = cnt;
last_st = st;
}
}
}
char* longestPalindrome(char* s) {
for(int i = 0;s[i] != '\0';i++) p++;
last_st = 0,Max = 0;
for(int k = 0;k <= p;k++){
mark = 1,cnt = 1,st = 0;
for(int i=k,j=p;s[i] != '\0';i++,j--){
findMaxlen(i,j,k,s);
}
mark = 1,cnt = 1,st = 0;
for(int i=0,j=p-k;i<=p-k;i++,j--){
findMaxlen(i,j,k,s);
}
}
char* ps = (char*)malloc((Max+1)*sizeof(char));
for(int i = 0;i < Max;i++) ps[i] = s[last_st + i];
ps[Max] = '\0';
for(int i = 0;ps[i] != '\0';i++) printf("%c",ps[i]);
return ps;
}
2 . DP解法(https://leetcode.com/problems/longest-palindromic-substring/solution/):
自己写的动态规划如下:
char* longestPalindrome(char* s) {
int n = 0,dp[1005][1005] = {0};
int st = 0,longest = 1;
for(int i=0;s[i] != '\0';i++){
dp[i][i] = 1;
n++;
}
for(int i=1;i < n;i++){
dp[i-1][i] = s[i-1] == s[i];
}
for(int i=0;i < n - 1;i++){
for(int j=i+2;j < n;j++){
dp[i][j] |= dp[i+1][j-1] && s[i] == s[j];
}
}
for(int i=0;i < n;i++){
for(int j=i + longest;j<n;j++){
if(dp[i][j]){
longest = j - i + 1;
st = i;
}
}
}
char* ps = (char*)malloc((longest + 1) * sizeof(char));
for(int i = 0;i < longest;i++) ps[i] = s[st+i];
ps[longest] = '\0';
return ps;
}
这个DP写的不对,比如 "abcba",按照上面的程序结果是 "bcb",因为其寻找回文字符串的顺序是不对,寻找最长的回文字符喜欢的顺序应该是由短到长,但是它是对于前 n - 1 个字符,依次确定从这个字符开始往后数1位 2 位 ....一直到末尾,这 n - i 个字符串是否是回文字符串,所以在判断较长的回文字符串的时候在其内部的回文字符串还没有被判是,就是导致较长的被判否。正确的顺序应该是,先找出所有长度为 i 的字符串之后再寻找长度位 i + 1 的字符串,参考这篇博客修改之后的程序如下:
char* longestPalindrome(char* s) {
int n = 0,dp[1005][1005] = {0};
int st = 0,longest = 1;
while(s[n] != '\0') n++;
for(int dl = 0;dl < n;dl++){
for(int i = 0;i + dl < n;i++){
int j = i + dl;
if(s[i] == s[j] && (dl <= 2 || dp[i+1][j-1])){
dp[i][j] = 1;
if(j - i + 1 > longest){
longest = j - i + 1;
st = i;
}
}
}
}
s[st + longest] = '\0';
return s + st;
}
3. 中心扩展法:寻找以每个字符为中心的最长回文字符串,有两种情况:奇数和偶数。
char* longestPalindrome(char* s) {
int n = 0,l,r,st = 0,Max = 1;
while(s[n] != '\0') n++;
for(int i = 0;i < n;i++){
l = i - 1,r = i + 1;
while(l >= 0 && r < n && s[l] == s[r]) l--,r++;
l++,r--;
if(r - l + 1 > Max) st = l,Max = r - l + 1;
l = i,r = i + 1;
while(l >= 0 && r < n && s[l] == s[r]) l--,r++;
l++,r--;
if(r - l + 1 > Max) st = l,Max = r - l + 1;
}
s[st + Max] = '\0';
return s + st;
}
Email:JingwangLi@outlook.com