1. 题目
2. 解答
我们定义状态 state[i][j] 表示子串 s[i, j] 是否为回文子串,如果 s[i, j] 为回文子串,并且有 s[i-1] == s[j+1],那么 s[i-1, j+1] 也为回文子串。状态转移方程为:
s t a t e [ i ] [ j ] = 1 如果 i = j state[i][j] = 1 \space 如果 \space i = j state[i][j]=1 如果 i=j
s t a t e [ i ] [ j ] = { s t a t e [ i + 1 ] [ j − 1 ] 如果 s [ i ] = = s [ j ] 0 如果 s [ i ] ! = s [ j ] state[i][j] = \begin{cases} state[i+1][j-1] &\text{如果 } s[i] == s[j] \\ 0 &\text{如果 } s[i] != s[j] \end{cases} state[i][j]={state[i+1][j−1]0如果 s[i]==s[j]如果 s[i]!=s[j]
注意我们需要自底向上更新状态,首先是长度为 1 的子串,再然后是长度为 2 的,一直递增下去。
以一个长度为 5 的字符串来举例,首先,对角线上的状态都为 1,因为只有一个字符的字符串肯定是回文串。
(i,j) | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
0 | ✔️ | ② | ③ | ④ | ⑤ |
1 | ❎ | ✔️ | ② | ③ | ④ |
2 | ❎ | ❎ | ✔️ | ② | ③ |
3 | ❎ | ❎ | ❎ | ✔️ | ② |
4 | ❎ | ❎ | ❎ | ❎ | ✔️ |
然后,接下来,我们需要判断长度为 2 的子串是否是回文串,比如 state[0][1]
,这时候只要满足 s[0]=s[1]
,那么 state[0][1]=1
,而按照状态转移方程,state[0][1]=state[1][0]
,所以,上图中打叉的无效的状态我们一开始需要都设置为 1。而如果 s[0]!=s[1]
,那么子串不是回文串,state[0][1]=0
。
然后,接下来,我们需要判断长度为 3 的子串是否是回文串,比如 state[0][2]
,这时候只要满足 s[0]=s[2]
,那么 state[0][2]=state[1][1]=1
。而如果 s[0]!=s[2]
,那么子串不是回文串,state[0][2]=0
。
以此类推,我们可以继续判断出长度为 4 和 5 的子串是否是回文子串 ,如果某个子串是回文子串,我们就更新一个最长的长度,待把上表中对角线上半部分的状态全部更新完,就可以获得最长回文子串的长度了。
string longestPalindrome(string s) {
int n = s.size();
if (n == 0) return s;
vector<bool> temp(n, true);
vector< vector<bool>> state(n, temp);
int max_len = 1;
int begin = 0;
int end = 0;
// 坐标差从 1 开始,也即长度为 2
for (int len = 1; len < n; len++)
{
for (int i = 0; i < n-len; i++)
{
int j = i + len;
if (s[i] == s[j])
state[i][j] = state[i+1][j-1];
else state[i][j] = false;
if (state[i][j])
{
if (j - i + 1 > max_len)
{
max_len = j - i + 1;
begin = i;
end = j;
}
}
}
}
string ret(s.begin()+begin, s.begin()+end+1);
return ret;
}
获取更多精彩,请关注「seniusen」!