LeetCode5.最长回文子串
Question
给你一个字符串
s
,找到s
中最长的回文子串。如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
Example
Example 1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
Example 2:
输入:s = "cbbd"
输出:"bb"
Idea
1 <= s.length <= 1000
s
仅由数字和英文字母组成
Solution1:最长回文子序列转递归版
//速度太低超时
int palindrome(string str, int l, int r, int count, int &last){
int maxlen = 0, last1 = 0, last2 = 0;
if(l == r) return 1 + count;
if(l > r) return 0 + count;
if(str[l] == str[r]) {
last = l;
return palindrome(str,l+1,r-1, count+2,last);
}
else {//注意这里需要区别传进去的变量
if(palindrome(str,l-(count>>1),r+(count>>1)-1,0,last1)> palindrome(str,l-(count>>1)+1,r+(count>>1),0,last2)){
last = last1;
maxlen = palindrome(str,l-(count>>1),r+(count>>1)-1,0,last1);
}
else{
last = last2;
maxlen = palindrome(str,l-(count>>1)+1,r+(count>>1),0,last2);
}
}
return maxlen;
}
class Solution {
public:
string longestPalindrome(string s) {
//最长回文序列递归转化而来
int ll = 0;
int maxlen = palindrome(s,0,s.size()-1, 0, ll);
if(ll != 0) ll = ll - (maxlen - 2 >> 1);
return s.substr(ll , maxlen);
}
};
Solution2-1:最长回文子序列转动态规划初版
//数组版本,速度略高于官方题解, 函数版
#define N 1001
//动态规划,数组中存的是区间内最长回文子串长度
class Solution {
public:
// 查找数组最大值
int findmax(int dpa[][N], int &ri, int n){
//max:最大长度 min:最大长度中最小区间
int max = 0, min = n;
for(int j = 1; j < n; j++){ //列
for(int i = 0; i < j; i++){ //行
if(dpa[i][j] >= max) {
min = j - i;
ri = i;
max = dpa[i][j];
}
else if (dpa[i][j] == max){
if(j-i < min){
ri = i;
min = j - i;
}
}
}
}
return max;
}
string longestPalindrome(string s) {
int len = s.size();
if(len < 2) return s;
int dp[N][N],tmp = 0, maxLen = 0, begin = len;
//初始化
memset(dp,0,sizeof(dp));
for(int i = 0; i < len; i++) dp[i][i] = 1;
//dp数组赋值
for(int r = 1; r < len; r++){
for(int l = 0; l + r < len; l++){
tmp = dp[l+1][l+r-1];
// 保证里面是真最长回文子串或者里面没有字符
if(s[l] == s[l+r] && dp[l+1][l+r-1] == (r-1)) tmp = dp[l+1][l+r-1] + 2;
else tmp = max(dp[l+1][l+r],dp[l][l+r-1]);
dp[l][l+r] = tmp;
}
}
maxLen = findmax(dp,begin,len);
return s.substr(begin,maxLen);
}
};
Solution2:最长回文子序列转动态规划版
//数组版本,速度略高于官方题解
#define N 1001
//动态规划,数组中存的是区间内最长回文子串长度
class Solution {
public:
string longestPalindrome(string s) {
int len = s.size();
if(len < 2) return s;
//此处N可以用len代替,但是速度没有宏定义快
int dp[N][N], tmp = 0, maxLen = 0, begin = len, min = len;
memset(dp,0,sizeof(dp));
//dp数组赋值
for(int i = 0; i < len; i++) dp[i][i] = 1;
for(int r = 1; r < len; r++){
for(int l = 0; l + r < len; l++){
// 保证里面是真最长回文子串或者里面没有字符
if(s[l] == s[l+r] && dp[l+1][l+r-1] == (r-1)) tmp = dp[l+1][l+r-1] + 2;
else tmp = max(dp[l+1][l+r],dp[l][l+r-1]);
//查找最大值,最大值点区间最小值的左坐标并记录
if(tmp > maxLen) {
min = r;
begin = l;
maxLen = tmp;
}
else if (tmp == maxLen){
if(r < min){
begin = l;
min = r;
}
}
dp[l][l+r] = tmp;
}
}
return s.substr(begin,maxLen);
}
};
// vector版本:速度比数组更慢,内存占用更多
//动态规划,数组中存的是区间内最长回文子串长度
class Solution {
public:
string longestPalindrome(string s) {
int len = s.size();
if(len < 2) return s;
int tmp = 0, maxLen = 0, begin = len, min = len;
vector<vector<int>> dp(len, vector<int>(len, 0));
//dp数组赋值
for(int i = 0; i < len; i++) dp[i][i] = 1;
for(int r = 1; r < len; r++){
for(int l = 0; l + r < len; l++){
// 保证里面是真最长回文子串或者里面没有字符
if(s[l] == s[l+r] && dp[l+1][l+r-1] == (r-1)) tmp = dp[l+1][l+r-1] + 2;
else tmp = max(dp[l+1][l+r],dp[l][l+r-1]);
//查找最大值,最大值点区间最小值的左坐标并记录
if(tmp > maxLen) {
min = r;
begin = l;
maxLen = tmp;
}
else if (tmp == maxLen){
if(r < min){
begin = l;
min = r;
}
}
dp[l][l+r] = tmp;
}
}
return s.substr(begin,maxLen);
}
};
Solution3:自我简单尝试
//速度高于动态规划版本
class Solution {
public:
string longestPalindrome(string s) {
int len = s.size();
int r = len - 1, maxlen = 0, rl = 0;
//右逼近 采用maxlen 可以提前终止提升效率
while(maxlen <= r){
int l = 0;
while(l <= r){
int xl = l, xr = r;
//逐位判断回文
while(xl <= xr && s[xr] == s[xl]){
xr--;
xl++;
}
//判断是否是最长回文
if(xr < xl && (r - l + 1) > maxlen) {
rl = l;
maxlen = r - l + 1;
break;
}
l++;
}
r--;
}
if(maxlen != 0) return s.substr(rl, maxlen);
else return "";
}
};
Solution4:官方题解版动态规划
class Solution {
public:
string longestPalindrome(string s) {
int n = s.size(), maxlen = 1, begin = 0;
if(n < 2)return s;
vector<vector<int>> dp(n, vector<int>(n));
for(int i = 0; i < n; i++){
dp[i][i] = true;
}
for(int len = 1; len < n; len++){
for(int l = 0; l + len < n; l++){
if(s[l] != s[l+len]) dp[l][l+len] = false;
else if(len < 3) dp[l][l+len] = true; //串长为2或3 不用往内
else dp[l][l+len] = dp[l + 1][l+len - 1];
if (dp[l][l+len] && len + 1 > maxlen) { //len+1为串长,找到最大true区间
maxlen = len+ 1 ;
begin = l;
}
}
}
return s.substr(begin, maxlen);
}
};