代码随想录-2023/08/26

65 阅读1分钟

动态规划

647.回文子串

解题思路: 注意解决回文问题时,需要从内向外考虑, 考虑dp[i][j]的值根据dp[i+1][j-1]来推导

  1. dp[i][j]: 代表si开始, 以j结束的区间内回文子串的数量
  2. 当两个点字符相等时:
  • 若内部是回文子串, 则回文子串数量 + 1, 同时记录回文子串
  • 若内部不是回文子串, 则数量不变, 且回文子串标志置为false
  1. 考虑dp[i][j]的值根据dp[i+1][j-1]来推导, 所以dp数组必须是从左到右, 从下到上遍历, 即i逆序, j升序

代码:

class Solution {
    public int countSubstrings(String s) {
        int n = s.length();
        // dp[i][j]: 代表s以i开始, 以j结束的区间内回文子串的数量
        boolean[][] dp = new boolean[n][n];
        int res = 0;
        // 从O(n^3) 优化为 O(n^2) --- 注意递推公式(逆序)
        for(int i=n-1; i >= 0; i--){
            for(int j=i; j < n; j++){
                if(s.charAt(i) == s.charAt(j) && (j - i < 2 || dp[i+1][j-1])){
                    dp[i][j] = true;
                    res++;
                }
            }
        }
        return res;
    }
}

516.最长回文子序列

解题思路: 从内向外考虑

  1. s[i] == s[j]:则最长回文子序列的长度 需要 +2
  2. 若若s[i] != s[j]:则等于将左边字符进行匹配或者右边字符进行匹配时的最长序列 最大值(因为之前都计算过)

代码:

class Solution {
    // 求最长回文子序列, 类似于求最长单调递增子序列 --- 求最长单调递增子数组
    public int longestPalindromeSubseq(String s) {
        int n = s.length();
        int[][] dp = new int[n][n];
        for(int i=0; i<n; i++) dp[i][i] = 1;
        int ans = 0;
        for(int i=n-1; i>=0; i--){
            for(int j=i + 1; j < n; j++){
                if(s.charAt(i) == s.charAt(j)){
                    dp[i][j] = dp[i+1][j-1] + 2;
                }else{
                    dp[i][j] = Math.max(dp[i][j-1], dp[i+1][j]);
                }

            }
        }
        return dp[0][n-1];
    }
}