Leetcode:最长回文子串
题目
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。
测试案例
输入: "babad"
输出: "bab"
注意: "aba"也是一个有效答案。
输入: "cbbd"
输出: "bb"
解法
首先是最容易想到的复杂度最高的朴素遍历解法:
class Solution {
public:
string longestPalindrome(string s) {
if (s.empty()) return "";
if (s.size() == 1) return s;
int start=0,maxLength = 1;
for (int i = 0; i < s.size(); ++i)
{
for (int j = i + 1; j < s.size(); ++j)
{
int fFirst = i, fLast = j;
for (; fFirst < fLast; fFirst++, fLast--)
{
if (s[fFirst] != s[fLast])
break;
}
if (fFirst >= fLast && j - i + 1 > maxLength)
{
maxLength = j - i + 1;
start = i;
}
}
}
return s.substr(start, maxLength);
}
};
然后在介绍一种动态规划的方法:
\(dp[i,j]=
\begin{cases}
dp[i+1,j-1]& \text{s[i]=s[j]}\\
0& \text{s[i]!=s[j]}
\end{cases}\)
上面的状态转移方程表示,当s[i]=s[j]时,如果s[i+1...j-1]是回文串,则s[i...j]也是回文串;如果s[i+1...j-1]不是回文串,则s[i...j]不是回文串。
string longestPalindrome(string s) {
if (s.empty()) return "";
if (s.size() == 1) return s;
int len = s.size(),start=0,maxLength=1;
vector<vector<int>> dp(len, vector<int>(len));
//首先判断相邻2个字符
for (int i = 0; i < len; ++i)
{
dp[i][i] = 1;
if (i < len - 1)
{
if (s[i] == s[i + 1])
{
dp[i][i + 1] = 1;
start = i;
maxLength = 2;
}
}
}
//再从字符串长度为3开始判断
for (int l = 3; l <=len; ++l)
{
for (int i = 0; i+l-1 < len ; ++i)
{
int j = l+ i - 1;
if (s[i] == s[j] && dp[i + 1][j - 1] == 1)
{
dp[i][j] = 1;
start = i;
maxLength = l;
}
}
}
return s.substr(start, maxLength);
}
我们可以这样想,一个字符的话是回文字串,直接返回u;如果是两个相同的字符的话,那么字符串最长回文字符串的长度为2;之后利用动态规划的思想,如果一个新的字符串(原字符串的子串)的首尾字符相同,同时除了首尾的字符串刚好是上一个动态规划的结果,那么就可以将这个字符串作为下一次判断的依据,如果下一次不是则就保存结果。代码中dp[i+1][j+1]
就是上一次的字符串判断结果。
然后贴一下大神的Manacher解法
作者:YunLambert
-------------------------------------------
个性签名:一名会音乐、爱健身的不合格程序员
可以Follow博主的Github哦(っ•̀ω•́)っ✎⁾⁾