5. Longest Palindromic Substring
- Total Submissions: 539109
- Difficulty: Medium
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.
解析:
1.暴力解法,时间复杂度O(n^3),此种方法时间超出,未能AC。
string longestPalindrome(string s) {
int i, j, len = s.length();
int maxn=0,cnt = 0;
string res="";
for (i = 0; i<len; ++i){
for (j = i; j<len; ++j){
for (int k = 0; j - k >= 0 && i + k <= len&&i + k <= j - k; ++k){
if (s[i + k] == s[j - k]){
cnt++;
}
else{
break;
}
}
if (((j - i + 1) % 2==0 && cnt == (j - i + 1) / 2)||((j-i+1)%2==1&&(cnt==(j-i+1)/2+1))){
if (j - i >= maxn){
maxn = j - i;
res = s.substr(i, j - i + 1);
}
}
cnt = 0;
}
}
return res;
}
2.动态规划解法
假设dp[i][j]的值为true,表示字符串s中下标从i到j的字符组成的子串是回文串。那么可以推出:
dp[i][j]=dp[i+1][j-1]&&s[i]==s[j]
这是一般的情况,由于需要依靠i+1,j-1,所以有可能i+1=j-1,i+1=(j-1)-1,因此需要求出基准情况才能套用以上公式。
a. i+1 = j-1 ,即回文长度为1时,dp[i][i]=true;
b. i+1 = (j-1)-1,即回文长度为2时,dp[i][i+1]=(s[i]==s[i+1])。
string longestPalindrome02(string s){
int n = s.length();
bool **dp = new bool*[n];
for (int i = 0; i < n; ++i){
dp[i] = new bool[n];
}
//基准情况
int start = 0;
int max = 1;
for (int i = 0; i < n; ++i){
dp[i][i] = true;
if (i + 1 < n){
if (s[i] == s[i + 1]){
dp[i][i + 1] = true;
start = i;
max = 2;
}
else dp[i][i + 1] = false;
}
}
//动态规划求解,前面已经求解了len = 1 ,len = 2的情况了
for (int len = 3; len <= n; ++len){
for (int i = 0; i < n - len + 1; ++i){
int j = i + len - 1;
if (dp[i+1][j-1]&&s[i]==s[j]){
dp[i][j] = true;
int curLen = j - i + 1;
if (curLen>max){
start = i;
max = curLen;
}
}
else dp[i][j] = false;
}
}
for (int i = 0; i < n; ++i){
delete[] dp[i];
delete[] dp;
return s.substr(start,max);
}
}
此种方法 内存超出,未能AC。
3.中心扩展法
因为回文字符串是以中心轴对称的,所以如果我们从下标i出发,用2个指针向i的两边扩展判断是否相等,那么只需要对0到n-1的下标都做此操作,就可以求出最长的回文子串。
但需要注意的是,回文字符串有奇偶对称之分,即“abcba”和“abba”2种类型。
因此需要在代码中做出判断。
设int Palindromic(string &s,int i,int j)是求下标i和j向两边扩展的回文串的长度,那么对0至n-1的下标,调用两次此函数:
int lenOdd = Palindromic(str,i,i)和int lenEven = Palindromic(str,i,j),即可求得以i下标为奇回文和偶回文的子串长度。
接下来以lenOdd和lenEven中的最大值与当前最大值max比较即可。
这个方法有一个好处是时间复杂度为O(n^2),且不需要使用额外的空间。
class Solution {
public:
string longestPalindrome(string s){
int n = s.length();
int start = 0;
int maxn = 1;
for (int i = 0; i < n; ++i){
int oddLen = 0, evenLen = 0, curLen;
oddLen = Palindromic(s, i, i);
if (i + 1 < n){
evenLen = Palindromic(s, i, i + 1);
}
curLen = oddLen > evenLen ? oddLen : evenLen;
if (curLen>maxn){
maxn = curLen;
if (maxn & 0x1){
start = i - maxn / 2;
}
else{
start = i - (maxn - 1) / 2;
}
}
}
return s.substr(start, maxn);
}
public:
int Palindromic(string &str,int i,int j){
int n = str.length();
int curLen = 0;
while (i >= 0 && j < n&&str[i] == str[j]){
--i; ++j;
}
curLen = (j - 1) - (i + 1) + 1;
return curLen;
}
};
46ms,AC
第四种解法:Manacher算法的O(n)的算法,下次更新