647. 回文子串
给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。 回文字符串 是正着读和倒过来读一样的字符串。 子字符串 是字符串中的由连续字符组成的一个序列。 具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
示例 1: 输入:s = "abc" 输出:3 解释:三个回文子串: "a", "b", "c" 示例 2: 输入:s = "aaa" 输出:6 解释:6个回文子串: "a", "a", "a", "aa", "aa", "aaa"
提示:
- 1 <= s.length <= 1000
- s 由小写英文字母组成
思路
为了统计字符串中回文子串的数量,我们可以使用动态规划的方法。这里是一个可能的解决方案的步骤:
- 确定dp数组以及下标的含义:
dp[i][j]表示字符串从索引i到j的子串是否是回文串。如果是回文串,dp[i][j]为true,否则为false。
- 确定递推公式:
- 如果
s[i] == s[j],那么我们需要检查里面的子串s[i+1...j-1]是否是回文串,这可以通过dp[i+1][j-1]来判断。如果里面的子串是回文串,那么dp[i][j]也是回文串。 - 如果
s[i] != s[j],那么dp[i][j]显然不是回文串。 - 递推公式为:
dp[i][j] = (s[i] == s[j]) && (j - i < 3 || dp[i+1][j-1])。
- dp数组如何初始化:
- 所有的
dp[i][i]都应该初始化为true,因为每个单独的字符都是回文串。 - 其余的
dp[i][j]初始化为false。
- 确定遍历顺序:
- 由于
dp[i][j]依赖于dp[i+1][j-1],我们需要从下往上,从左到右进行遍历。
- 举例推导dp数组:
- 以字符串
s = "aaa"为例,dp[0][0]、dp[1][1]、dp[2][2]都应该为true。 dp[0][1]会检查s[0]和s[1]是否相等,以此类推。
题解
class Solution {
public:
int countSubstrings(string s) {
int n = s.size();
vector<vector<bool>> dp(n, vector<bool>(n, false));
int count = 0;
for (int i = n - 1; i >= 0; --i) {
for (int j = i; j < n; ++j) {
if (s[i] == s[j] && (j - i < 3 || dp[i + 1][j - 1])) {
dp[i][j] = true;
count++;
}
}
}
return count;
}
};
516. 最长回文子序列
给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。 子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。
示例 1: 输入:s = "bbbab" 输出:4 解释:一个可能的最长回文子序列为 "bbbb" 。 示例 2: 输入:s = "cbbd" 输出:2 解释:一个可能的最长回文子序列为 "bb" 。
提示:
- 1 <= s.length <= 1000
- s 仅由小写英文字母组成
思路
- 确定dp数组以及下标的含义:
dp[i][j]表示字符串从索引i到j的子序列中,最长回文子序列的长度。
- 确定递推公式:
- 如果
s[i] == s[j],那么dp[i][j] = dp[i+1][j-1] + 2。 - 如果
s[i] != s[j],那么dp[i][j] = max(dp[i+1][j], dp[i][j-1])。
- dp数组如何初始化:
- 所有的
dp[i][i]都应该初始化为1,因为每个单独的字符都是一个长度为1的回文子序列。 - 其余的
dp[i][j]初始化为0。
- 确定遍历顺序:
- 由于
dp[i][j]依赖于dp[i+1][j-1],dp[i+1][j]和dp[i][j-1],我们需要从下往上,从左到右进行遍历。
- 举例推导dp数组:
- 以字符串
s = "bbbab"为例,dp[0][4]会检查s[0]和s[4]是否相等,以此类推。
题解
class Solution {
public:
int longestPalindromeSubseq(string s) {
int n = s.size();
vector<vector<int>> dp(n, vector<int>(n, 0));
// 初始化dp数组
for (int i = 0; i < n; ++i) {
dp[i][i] = 1;
}
// 从下往上,从左到右遍历
for (int i = n - 1; i >= 0; --i) {
for (int j = i + 1; j < n; ++j) {
if (s[i] == s[j]) {
dp[i][j] = dp[i + 1][j - 1] + 2;
} else {
dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
}
}
}
return dp[0][n - 1];
}
};