个人主页:元清加油_【C++】,【C语言】,【数据结构与算法】-CSDN博客
个人专栏
力扣递归题
【C++】
http://t.csdnimg.cn/6AbpV
数据结构
前言:这个专栏主要讲述动态规划算法,所以下面题目主要也是这些算法做的
我讲述题目会把讲解部分分为3个部分:
1、题目解析
2、算法原理思路讲解
3、代码实现
回文子串
题目链接:回文子串
题目
给你一个字符串 s
,请你统计并返回这个字符串中 回文子串 的数目。
回文字符串 是正着读和倒过来读一样的字符串。
子字符串 是字符串中的由连续字符组成的一个序列。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
示例 1:
输入:s = "abc" 输出:3 解释:三个回文子串: "a", "b", "c"
示例 2:
输入:s = "aaa" 输出:6 解释:6个回文子串: "a", "a", "a", "aa", "aa", "aaa"
提示:
1 <= s.length <= 1000
s
由小写英文字母组成
解法
算法原理与解析
我们这题使用动态规划,我们做这类题目可以分为以下五个步骤
- 状态显示
- 状态转移方程
- 初始化(防止填表时不越界)
- 填表顺序
- 返回值
- 状态显示
为了能表示出来所有的子串,我们可以创建⼀个
n*n
的二维
dp
表,只⽤到「上三⻆部分」
即可。 其中, dp[ i ][ j ] 表示
:
s
字符串
[i, j]
的⼦串,是否是回文串。
- 状态转移方程
对于回文串,我们⼀般分析⼀个「区间两头」的元素:
- 当 s[i] != s[j] 的时候:不可能是回⽂串, dp[i][j] = 0 ;
- 当 s[i] == s[j] 的时候:根据长度分两种情况讨论
- 长度小于等于为 2 ,也就是 i + 1 == j 或 i == j:此时也⼀定是回⽂串, dp[i][j] = true ;
- 长度大于 2 ,此时要去看看 [i + 1, j - 1] 区间的⼦串是否回⽂: dp[i][j] = dp[i + 1][j - 1]
- 初始化(防止填表时不越界)
无需初始化
- 填表顺序
根据「状态转移⽅程」,我们需要「从下往上」填写每⼀⾏,每⼀⾏的顺序⽆所谓。
- 返回值
根据「状态表⽰和题⽬要求」,我们需要返回
dp
表中
true
的个数。
代码实现
class Solution {
public:
int countSubstrings(string s)
{
int n = s.size();
vector<vector<bool> > dp(n, vector<bool>(n)); // 表示以i为开头j为结尾的字符串是否为回文子串
int ans = 0; // 记录回文子串的个数
// 从下向上填表
for (int i = n - 1; i >= 0; i--)
{
for (int j = i; j < n; j++)
{
if (s[i] == s[j])
{
// 长度小于等于2那么一定是回文子串,若大于2则看dp[i+1][j-1]
dp[i][j] = i + 1 < j ? dp[i + 1][j - 1] : true;
}
if (dp[i][j])
{
ans += 1;
}
}
}
return ans;
}
};