「代码随想录算法训练营」第四十天 | 动态规划 part13

647. 回文子串

题目链接:https://leetcode.cn/problems/palindromic-substrings/
文章讲解:https://programmercarl.com/0647.回文子串.html
题目难度:中等
视频讲解:https://www.bilibili.com/video/BV17G4y1y7z9/
题目状态:看题解

思路一:动态规划

使用一个二维动规数组dp[i][j]来保存从s[i]s[j](或从s[j]s[i],一样的,本题代码是从j到i)是否属于回文子串。两层遍历该字符串,来记录回文子串的个数。

  • s[i] == s[j]时,要判断一下ij的距离,若i和j的距离为0和1,则表示这是一个回文子串。
  • s[i] == s[j]时,但ij的距离较大,那么就要看其里面的一个是不是回文子串。

代码一:

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

思路二:双指针

使用一个辅助函数extend来遍历有多少子串,其中i和j分别是两个起点指针,两个指针分别向前和向后遍历,如果遇到i不等于j的时候,就可以返回了,结果就是以i和j为中间点的子串有多少。而在主函数中,两次调用extend函数分别表示奇子串和偶子串。

代码二:

class Solution {
public:
    int countSubstrings(string s) {
        int ans = 0;
        for(int i = 0; i < s.size(); ++i) {
            ans += extend(s, i, i, s.size());
            ans += extend(s, i, i + 1, s.size());
        }
        return ans;
    }
    int extend(const string &s, int i, int j, int n) {
        int ans = 0;
        while(i >= 0 && j < n && s[i] == s[j]) {
            i--;
            j++;
            ans++;
        }
        return ans;
    }
};

516. 最长回文子序列

题目链接:https://leetcode.cn/problems/longest-palindromic-subsequence/
文章讲解:https://programmercarl.com/0516.最长回文子序列.html
题目难度:中等
视频讲解:https://www.bilibili.com/video/BV1d8411K7W6/
题目状态:看题解

思路:

维护一个动规数组dp[i][j]表示从s[i]s[j]的最长回文子序列的大小。

  • s[i] == s[j]时,表示其是一个回文序列,因此将这两个字符加入进来,即dp[i][j] = dp[i + 1][j - 1] + 2
  • s[i] != s[j]时,我们就需要找在这个范围里的最大子序列的个数了。

代码:

class Solution {
public:
    int longestPalindromeSubseq(string s) {
        int len = s.size();
        vector<vector<int>> dp(len, vector<int>(len, 0));
        for(int i = 0; i < len; ++i) dp[i][i] = 1;
        for(int i = len - 1; i >= 0; --i) {
            for(int j = i + 1; j < len; ++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][len - 1];
    }
};

动态规划总结

image

posted @ 2024-08-17 14:50  云雀AC了一整天  阅读(15)  评论(0编辑  收藏  举报