給定一個字符串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度爲1000。
示例 1:
輸入: “babad”
輸出: “bab”
注意: "aba"也是一個有效答案。
示例 2:
輸入: “cbbd”
輸出: “bb”
迴文串的定義我就不囉嗦了。對於這道題,我的第一反應是用動態規劃方法解。
假設字符串s的長度爲length,建立一個length*length的矩陣dp。
dp[i][j]表示“以s[i]開始s[j]結尾的迴文串的長度。如果這個字符串不是迴文串,讓dp[i][j]=0”。顯然,j>=i,只需往dp填j>=i的部分即可。
dp[i][j]的遞推公式可以這麼表述:
(1)首先對dp的對角線元素初始化爲1,也就是當i==j時,dp[i][j]=1。
這很顯然,每個單獨的字符其實就是個長度爲1的迴文串。
(2)當j-i==1:
若s[i]==s[j],則dp[i][j]=2;否則dp[i][j]=0。
解釋:當j-i==1時,若s[i]==s[j],則s[i]和s[j]可以組成一個長度爲2的迴文串。若s[i]!=s[j],顯然他們不可能組成迴文串,dp[i][j]=0。
(3)當j-i>=2:
若s[i]==s[j]:若dp[i+1][j-1]>0,則dp[i][j]= dp[i + 1][j - 1] + 2;否則dp[i][j]= 0;
若s[i]!=s[j]:dp[i][j]=0。
解釋:如果s[i]==s[j],表明這個子串有可能是迴文串。當去頭去尾後它是迴文串時,就可以在去頭去尾的那個迴文串長度基礎上+2,得到它的長度。如果去頭去尾後不是迴文串,那這個子串一定不是迴文串,迴文串長度只能是0。
若s[i]!=s[j],顯然他們不可能組成迴文串,dp[i][j]=0。
只需找到dp[i][j]的最大元素和它對應的i和j就可以得到結果“s中最長迴文子串”。
另外還有一個要注意的點:因爲需要訪問dp[i+1][j-1],因此i是從大到小的,j是從小到大的。j從0到size-1,i從j-1到0。
#include "iostream"
#include "string"
#include "sstream"
#include "vector"
#include "algorithm"
using namespace std;
int main()
{
string str =" ";
while (getline(cin, str))
{
int len = str.length();
vector<vector<int>> dp(len + 1, vector<int>(len + 1, 0)); //dp[i][j]表示字符串第i個開始和字符串第j個結束之間的迴文長度
for(int i = 1; i < len + 1; i++)
for (int j = 1; j < len + 1; j++)
{
if (i == j)
dp[i][j] = 1; //對角線的元素置爲1,因爲單獨字符的迴文長度爲1
}
int max_len = 0;
int start = 0;
for(int j = 1; j< len+1 ; j++)//以結束爲止爲外循環,每次循環完畢則得到以此爲終點的最長迴文串
for (int i = j - 1; i >= 1; i--)
{
if (str[i - 1] == str[j - 1])//起、終元素一樣
{
if (j - i == 1) //如果長度差1
dp[i][j] = 2;
else
{
if (dp[i + 1][j - 1] > 0) //長度差大於2,就看是一個串是不是迴文
dp[i][j] = dp[i + 1][j - 1] + 2;
else
dp[i][j] = 0;
}
}
else
dp[i][j] = 0;
if (dp[i][j] > max_len)
{
max_len = dp[i][j];
start = i-1;
}
}
string s = str.substr(start, max_len);
cout << s << endl;
}
}