● 647. 回文子串 ● 516.最长回文子序列 ● 动态规划总结篇

● 647. 回文子串  

1.dp数组含义。

之前的题目,差不多都是求什么就怎么定义dp数组,最后返回dp的最后一个元素。但是这里如果定义一维数组dp[i]是[0,i]范围的回文子串的个数的话,怎么根据dp[i-1]得到dp[i]?发现很难找到递归关系,回文串需要固定两端来讨论判断。

所以需要二维数组。又:dp数组不统计个数,而是判断是否是回文子串的话,比较好推导递归关系:因为根据回文子串的定义,如果下标1、2、3组成的子串是回文串,那么只需要下标0和4的字符相等,就可以判定为回文子串。而统计个数的话还是需要比较中间所有的元素。

所以dp[i][j]:下标范围为[i,j]的子串是否回文,是为true,否为false。i、j都是闭区间,当i=j的时候就是单个字符,好初始化。

最后返回dp数组中值为true的个数。

2.递推公式。

参照上图,如果s[i]==s[j]而且中间的子串[i+1,j-1]是回文子串的话,那么[i,j]子串肯定是回文子串。这个图只考虑了i和j中间至少一个元素的情况,实际上在相等的条件下根据i和j的大小,得到dp[i][j]有3种情况:

①i==j:就一个字符,[i,j]是回文子串。

②j==i+1:2个字符,只要满足一个条件:s[i]==s[j],就是一个回文子串。

③j>i+1:有≥2个字符,只要满足相等和dp[i+1][j-1]=true这两个条件的话,[i,j]就是回文子串。

所以dp[i][j]在上面3种情况中=true,其他的都是false,可以直接在初始化的时候设定。因为这里的条件且和或 的逻辑有点多,所以就分开写:
 

if(s[i]==s[j]){
  if(j<=(i+1))//情况1和2
  {
      dp[i][j]=true;
      count++;
  }
  if(i<n-1&&j>0&&dp[i+1][j-1]){//情况3
      dp[i][j]=true;
      count++;
  }
}

3.初始化。

在一开始定义dp数组的时候,我们就所有元素都初始化为false,到递推的时候再把每个元素更新为true。

注意情况①没有在初始化时设定,本来这个递推比较耗时间,在循环前面初始化的话有2个例子会超时。

4.遍历顺序。

这题的遍历顺序踩坑了,其实这个dp数组是一个对称矩阵,我们只需要统计对角线上true的个数加上:左下角或者右上角的true个数即可。再看定义的时候,我们说范围[i,j]内的,所以定为i<=j,即统计的是对角线+右上角的。又因为dp[i][j]是否为true取决于dp[i+1][j-1],[i+1,j-1]是在[i,j]的左下角,说明到达i、j的时候,左下角的dp是需要更新了的。所以在i<=j的前提下:

(1)先列后行(先j后i):

for(int j=0;j<n;++j){
            for(int i=0;i<=j;++i){
}}

(2)先行后列(先i后j)

for(int i=n-1;i>=0;--i){
            for(int j=i;j<n;++j){
}}

告诉我们遍历顺序需要简画一下dp数组的结构图。

5.打印。

代码如下。列优先的情况需要增加条件i<n-1 && j>0,行优先的话不需要添加。

class Solution {
public:
    int countSubstrings(string s) {
        int n=s.size();
        int count=0;
        vector<vector<bool>> dp(n,vector<bool>(n,false));
        for(int j=0;j<n;++j){
            for(int i=0;i<=j;++i){
                    if(s[i]==s[j]){
                        if(j<=(i+1))
                        {
                            dp[i][j]=true;
                            count++;
                        }
                        if(i<n-1&&j>0&&dp[i+1][j-1]){
                            dp[i][j]=true;
                            count++;
                        }
                        
                    }
                
                cout<<dp[i][j]<<"  ";
            }
        }
        return count;
    }
};


● 516.最长回文子序列


● 动态规划总结篇

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-20 06:26:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-20 06:26:03       101 阅读
  3. 在Django里面运行非项目文件

    2024-03-20 06:26:03       82 阅读
  4. Python语言-面向对象

    2024-03-20 06:26:03       91 阅读

热门阅读

  1. C/C++蓝桥杯之卡片问题

    2024-03-20 06:26:03       41 阅读
  2. opencv逐帧获取视频图片

    2024-03-20 06:26:03       47 阅读
  3. 尚硅谷数据库|视图/存储过程与函数/流程控制

    2024-03-20 06:26:03       37 阅读
  4. nginx日志统计qps

    2024-03-20 06:26:03       42 阅读
  5. 记一次Jenkins打包镜像报错问题

    2024-03-20 06:26:03       35 阅读
  6. 机器学习和大模型的关系,怎么入门

    2024-03-20 06:26:03       47 阅读
  7. ElementPlus布局出现“xx/index.vue“. Does the file exist?

    2024-03-20 06:26:03       45 阅读
  8. C++开发基础——可变参数与可变参数模板

    2024-03-20 06:26:03       36 阅读