算法训练1-day39-动态规划

20 阅读1分钟
  1. 647. 回文子串

本题如果我们定义,dp[i] 为 下标i结尾的字符串有 dp[i]个回文串的话,我们会发现很难找到递归关系。 我们在判断字符串S是否是回文,那么如果我们知道 s[1],s[2],s[3]这个子串是回文的,那么只需要比较 s[0]s[4]这两个元素是否相同,如果相同的话,这个字符串s 就是回文串。 因此,dp[i][j]:表示区间范围[i,j](注意是左闭右闭)的子串是否是回文子串,如果是dp[i][j]为true,否则为false。

AC代码:

class Solution {
public:
    int countSubstrings(string s) {
        int n = s.length();
        // dp[i][j]:[i,j]范围内的子串是否是回文
        vector<vector<bool>> dp(n, vector<bool>(n));
        int res = 0;
        for (int i = n - 1; i >= 0; --i) {
            for (int j = i; j < n; ++j) {
                if (s[i] == s[j]) {
                    if (j - i <= 1) {
                        res++;
                        dp[i][j] = true;
                    } else if (dp[i + 1][j - 1]) {
                        res++;
                        dp[i][j] = true;
                    }
                }
            }
        }

        return res;
    }
};
  1. 516. 最长回文子序列

647. 回文子串类似,对于回文的问题,dp的定义一般都是看一个范围内是否是回文,然后向左右两边扩散递归。 本题也是类似,dp数组:[i,j]范围内的子序列的最长回文子序列

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