最长回文子串
题目描述:给定一个字符串,找到其中最长回文子串。
解题思路:
1、中心扩展法:
遍历字符串s, 以s[i]为中心,设置左右指针,做为判断字符串的边界,向两边查找最长回文字符串。整个过程进行迭代,但是由于最长回文子串的长度分为奇偶,所以它的中心个数也分为奇偶。
#include <iostream>
using namespace std;
class Solution {
public:
int maxn=0;
string ret="";
void helper(string &s,int left,int right)
{
int l=left,r=right;
while(l>=0&&r<s.size()&&s[l]==s[r])
{
if(r-l+1>maxn)
{
maxn=r-l+1;
ret=s.substr(l,r-l+1);
}
l--;
r++;
}
}
string longestPalindrome(string s) //中心扩展法
{
if(s.size()<=1) return s;
for(int i=0;i<s.size();i++)
{
helper(s,i,i);
helper(s,i,i+1);
}
return ret;
}
};
int main()
{
string s="abcdbbc";
Solution S;
cout<<S.longestPalindrome(s)<<endl;
return 0;
}
2、动态规划
定义的动态方程为dp[i][j],代表从字符串i—j的位置是否是回文串,
如果长度<4 那么直接判断中心的两侧是否相等,比如bab,aa,c;
如果长度>=4 dp[i][j]=dp[i+1][j-1]
class Solution
{
public:
string longestPalindrome(string s)
{
int n = s.size();
if (n < 2)
{
return s;
}
int maxLen = 1;
int begin = 0;
vector<vector<int>> dp(n, vector<int>(n));
//所有长度为 1 的子串都是回文串
for (int i = 0; i < n; i++)
dp[i][i] = true;
for (int L = 2; L <= n; L++) ///枚举长度,包括n
{
///枚举左边界,左边界的上限设置可以宽松一些
for (int i = 0; i < n; i++)
{
// 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
int j = L + i - 1;
// 如果右边界越界,就可以退出当前循环
if (j >= n) break; /// <=
if (s[i] != s[j]) dp[i][j] = false;
else
{
if (L < 4) dp[i][j] = true; ///长度为1-3个字符的时候,是回文
else ///长度大于3的时候,根据动态方程
dp[i][j] = dp[i + 1][j - 1];
}
// 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
if (dp[i][j] && j - i + 1 > maxLen)
{
maxLen = j - i + 1;
begin = i;
}
}
}
return s.substr(begin, maxLen);
}
};