-
问题描述
回文串是指这个字符串无论从左读还是从右读,所读的顺序是一样的;简而言之,回文串是左右对称的。现在,对于一个给定的母串
abcdedcb
可以找出子串a, ded, cdedc, bcdecdb等均是回文串;显然,bcdecdb是其中最长的那一个。但是该如何找出最长的回文子串呢?
问题解法
最容易想到的依然是穷举法,穷举所有子串,找出是回文串的子串,统计出最长的那一个。
穷举法
i, j的for循环表示字符串s[i..j],然后逐一判断,找出最长。
/*判断str[i..j]是否为回文串*/ int isPalindrome(char *str, int begin, int end) { while(str[begin] == str[end] && begin <= end) { begin++; end--; } if(str[begin] != str[end]) { return 0; } else { return 1; } } /*返回最长回文子串长度*/ int longestPald(char *str) { int len = strlen(str); int i, j; int longest = 1; assert(str != NULL); if(len == 1) { return 1; } for(i = 0; i<len; i++) { for(j=i+1; j<len; j++) { if(isPalindrome(str, i, j)) { longest = (longest < j-i+1 ? j-i+1: longest); } } } return longest; }
穷举法的时间复杂度为 O(n3) ,复杂度太高了,需要做一些改进。
======== 自己的做法: leetcode无法提交,时间复杂度太高了,总提示 time limit exceeded, ============
bool is_max_sub(char *s, int start, int end) {
if (start > end) return false;
if (start == end) return true;
while (start < end && s[start] == s[end]) {
start++;
end--;
}
if (start >= end)
return true;
else
return false;
}
char* longestPalindrome(char* s) {
int max_length=0;
int length=strlen(s);
int start, end, max_start, max_end;
for (start=0; start<length; start++) {
for(end=start; end<length; end++) {
if (is_max_sub(s, start, end)) {
if (max_length < (end-start+1)) {
max_length=end-start+1;
max_start=start;
max_end=end;
}
}
}
}
int i=0;
char * max_sub = malloc(sizeof(char) * (max_length+1));
for ( i =0; i<max_length; i++){
max_sub[i] = s[max_start];
max_start++;
}
max_sub[max_length]='\0';
return max_sub;
}
======== 自己的做法 ============
-
对穷举法的改进
回文串是左右对称的,如果从中心轴开始遍历,会减少一层循环。思路:依次以母串的每一个字符为中心轴,得到回文串;然后通过比较得到最长的那一个。注意:要考虑到像baccab这样的特殊子串,可以理解它的中心轴是cc。
/*以mid为中心轴的回文子串*/ int l2r(char *str, int mid) { int l = mid -1, r = mid+1; int len = strlen(str); while(str[r] == str[mid]) { r++; } while(l >= 0 && r < len && str[l] == str[r]) { l--; r++; } return r-l-1; } int longestPald(char *str) { int len = strlen(str); int i; int longest = 1; assert(str != NULL); if(len == 1) { return 1; } for(i = 0; i<len; i++) { if(l2r(str, i) > longest) longest = l2r(str, i); } return longest; }
- 时间复杂度: O(n2)
- .
- 空间复杂度:
O(1)
- .
动态规划
有母串s,我们用
c[i, j] = 1
表示子串s[i..j]为回文子串,那么就有递推式c[i,j]={c[i+1,j−1]0if s[i]=s[j]if s[i]≠s[j]递推式表示在
s[i] = s[j]
情况下,如果s[i+1..j-1]是回文子串,则s[i..j]也是回文子串;如果s[i+1..j-1]不是回文子串,则s[i..j]也不是回文子串。初始状态:
- c[i][i] = 1
- c[i][i+1] = 1 if s[i] == s[i+1]
上述式子表示单个字符、两个字符均是回文串。
int longestPald(char *str) { int len = strlen(str); int c[maxLen][maxLen]; int i,j; int longest = 1; assert(str != NULL); if(len == 1) { return 1; } //initialization for(i = 0; i < len; i++) { c[i][i] = 1; if(str[i] == str[i+1]) c[i][i+1] = 1; } for(i = 0; i < len; i++) { for(j = i+2; j <= len; j++) { if(str[i] == str[j]) { c[i][j] = c[i+1][j-1]; //find longest palindrome substring if(c[i][j]) { int n = j - i + 1; if(longest < n) longest = n; } } else { c[i][j] = 0; } } } return longest; }
- 时间复杂度: O(n2)
- .
- 空间复杂度: O(n2) .