问题描述:
给你一个字符串s,找到s中最长的回文子串。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-palindromic-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
示例1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例2:
输入:s = "cbbd"
输出:"bb"
示例3:
输入:s = "a"
输出:"a"
示例4:
输入:s = "ac"
输出:"a"
题目分析:
对于一个子串而言,如果它是回文串,并且长度大于 2,那么将它首尾的两个字母去除之后,它仍然是个回文串。可以采用动态规划的方法,设
P
(
i
,
j
)
P(i,j)
P(i,j)表示字符串
s
s
s的第
i
i
i到
j
j
j个字母组成的串(下文表示成
s
[
i
:
j
]
s[i:j]
s[i:j]是否为回文串):
P
(
i
,
j
)
=
{
t
r
u
e
如
果
子
串
s
i
…
s
j
是
回
文
串
f
a
l
s
e
其
他
情
况
P(i,j)=\begin{cases} true \quad\quad 如果子串s_{i} \ldots s_{j}是回文串\\ false \quad其他情况 \end{cases}
P(i,j)={true如果子串si…sj是回文串false其他情况
由此得到状态转移方程,即只有在
s
[
i
+
1
:
j
−
1
]
s[i+1:j-1]
s[i+1:j−1]是回文串且
S
i
=
S
j
S_{i}=S_{j}
Si=Sj时,
s
[
i
,
j
]
s[i,j]
s[i,j]才是回文串。
P
(
i
,
j
)
=
P
(
i
+
1
,
j
−
1
)
a
n
d
(
S
i
=
=
S
j
)
P(i,j)=P(i+1,j-1) \quad and \quad (S_{i}==S_{j})
P(i,j)=P(i+1,j−1)and(Si==Sj)
除此之外,还有长度为小于等于2的情况,对于长度为1的子串,它显然是个回文串;对于长度为2的子串,只要两个字母相同,它也是一个回文串。由此得到动态规划边界条件:
{
P
(
i
,
i
)
=
t
r
u
e
P
(
i
,
i
+
1
)
=
(
S
i
=
S
i
+
1
)
\begin{cases} P(i,i)=true \quad\quad \\ P(i,i+1)=(S_{i}=S_{i+1}) \quad \end{cases}
{P(i,i)=trueP(i,i+1)=(Si=Si+1)
结合上述两种情况,最终整合的结果为所有
P
(
i
,
j
)
=
t
r
u
e
P(i,j)=true
P(i,j)=true中
j
−
i
+
1
j-i+1
j−i+1(即子串长度)的最大值。
代码实现:
源程序:
/*
问题:寻找字符串s中的最长回文子串
*/
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Solution {
public:
string longestPalindrome(string s) {
int n = s.size();
vector<vector<int> > dp(n, vector<int>(n));
string ans;
for (int l = 0; l < n; ++l) {
for (int i = 0; i + l < n; ++i) {
int j = i + l;
if (l == 0) {
dp[i][j] = 1;
}
else if (l == 1) {
dp[i][j] = (s[i] == s[j]);
}
else {
dp[i][j] = (s[i] == s[j] && dp[i + 1][j - 1]);
}
if (dp[i][j] && l + 1 > ans.size()) {
ans = s.substr(i, l + 1);
}
}
}
return ans;
}
};
int main(int argc, char *argv[])
{
string s = "babad";
Solution lps;
string res = lps.longestPalindrome(s);
cout << res;
}
执行结果: