Leetcode我来了!一天一题的我,工作都找不到热乎的,得加快步伐了,GG。
读题心路历程:照样先自己来看题,想想自己要怎么写,这道题拿过来的一看的感觉,好像不难,自己去暴力遍历,什么是回文子串呢?就是正序和倒序是相同的字符串,类似中心对称的感觉吧。也就是我先遍历一遍,然后遍历的同时看遍历到的值的左右两端是否相等,相等肯定是回文串,这是一种情况,另一种情况就是,左右两端值不相等的时候,有一个和中间的相等就证明这两个字符是回文字符,自己的思路大概就是这些,然后还是按照标准动态规划的解题思路来解题。
这里就看了点Carl哥的,《代码随想录》——动态规划解题方法可以分为五部曲。
1)确定dp数组及其下标的含义:
用 dp[i][j] 表示,字符串 s 从第 i 个到第 j 个是不是回文子串。
在这里,dp[i][j] 为 true 代表此时的字符串中 i 到 j 的字符串是回文子串,false 就代表不是回文子串。通过遍历这个 nxn 的二维表格就可以算出,每一个表格的 true 或 false。以题中的例1 ——“babad” 为例,横纵分别待变第 i 或 j 个位置。
0(b) | 1(a) | 2(b) | 3(a) | 4(d) | |
0(b) | |||||
1(a) | |||||
2(b) | |||||
3(a) | |||||
4(d) |
举个例子:dp[0][2]就是代表字符串s中从第0个位置到第2个位置,这三个字符组成的字符串是不是回文子串,表格里的话,就是这样:
因为s[i]=s[j] && j-i<3,所以这是个回文子串,所以填true
0(b) | 1(a) | 2(b) | 3(a) | 4(d) | |
0(b) | true | ||||
1(a) | |||||
2(b) | |||||
3(a) | |||||
4(d) |
大致思路就是这样。
2)确定递推公式:
这道题中,如果一个字符串是回文子串,那么这个回文子串左右两端都添加一个相同的字符,那么添加后的字符肯定也是回文子串。所以在这里,可以确定递推公式:
相应的代码也可以确定出来了:
//首先定义一个nxn的二维数组dp,用来判断是不是回文子串。
vector<vector<bool>>dp(n,vector<bool>(n,false));
//这个nxn的表格里,对角线也就是 s[i][i] 均代表单个字符串,一个字符串肯定都是回文子串,所以在这里直接将表格中的对角线填充成true
for(int i=0;i<n;i++){dp[i][i]=true;}
for(int i=0;i<n;i++)
{
for(int j=1;j<n;j++)
{
if(s[i]=s[j])
{
dp[i][j] = j-i<3||dp[i+1][j-1];
}
else
{
dp[i][j] = false;
}
}
}
3)dp数组如何初始化
在这里可以判断一下,当 i = j 的时候dp[i][j]代表单个字符,就都是true也就都是1,所以可以将整个dp数组均初始话为0,也就是初始化为false。
1(b) | 2(a) | 3(b) | 4(a) | 5(d) | |
1(b) | true | ||||
2(a) | true | ||||
3(b) | true | ||||
4(a) | true | ||||
5(d) | true |
4)确定遍历顺序
遍历顺序的确定,主要依据递推公式来看。
5)举例推导dp数组
1(b) | 2(a) | 3(b) | 4(a) | 5(d) | |
1(b) | T | F | T | F | F |
2(a) | T | F | T | F | |
3(b) | T | F | F | ||
4(a) | T | F | |||
5(d) | T |
当dp数组遍历完,只需要统计 j - i 的最大值,就可以算出最长回文子串的大小了。
完整代码:
string longestPalindrome(string s) {
int n = s.size();
vector<vector<bool>> dp(n, vector<bool>(n,false));
for (int i = 0; i < n; i++) { dp[i][i] = true; }
for (int i = n-1; i >= 0; i--) {
for (int j = i+1; j <n; j++) {
if (s[i] != s[j])
{
dp[i][j] = false;
}
else {
dp[i][j] = j - i < 3 || dp[i + 1][j - 1];
}
}
}
int maxlen = 1;
int ibegin = 0;
//这一部分就是遍历二维数组,在是回文子串的地方判断j-i的大小
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (dp[i][j] && j - i + 1 > maxlen) {
maxlen = j - i + 1;
ibegin = i;
}
}
}
return s.substr(ibegin, maxlen);
}