730. Count Different Palindromic Subsequences

Hard
LinkedIn tag
花花酱 LeetCode 730. Count Different Palindromic Subsequences - 刷题找工作 EP114
思路上有很多细节要处理,但如果每一种情况都理清了的话也不难。

所有的情况:
主要的两大类是首位字符相同或不相同,首位字符相同的大类又分为三小类:就是除开首位两字符之外的中间字符含不含有首尾字符,不含?含有一个,还是含有两个或以上?


处理方法:
dp[i][j] = s[i,j]子字符串所包含的不同palindrome个数
对于首尾字符不相同的情况,处理方法只有一种:
dp[i][j] = dp[i+1][j] + dp[i][j-1] - dp[i+1][j-1]

image.png

对于首尾字符相同的大类,可能有三种细分情况:

  • 中间部分不含有首尾字符,这种情况最简单,比如"bccb", 则count("bccb") = count("cc")*2 + 2, 也就是dp[i][j] = dp[i+1][j-1] * 2 + 2. 乘以二是因为每个原字符串"cc"能组成的会文都可以再在外层两端包裹上bb, 比如c -> bcb, cc -> bccb; 加二是加上新增部分自己所能组成的回文:b, bb.
  • 中间部分含有一个首尾字符,这种情况是dp[i][j] = dp[i+1][j-1] * 2 + 1为什么比上面的情况少一呢,其实就是因为bcbcb这种情况,新增的能组成的回文b跟原来cbc就有的回文b重复了,所以新增部分其实只能组成bb这一个新增回文,所以是加一
  • 中间部分含有两个或以上个首尾字符。 这种情况是dp[i][j] = dp[i+1][j-1] * 2 - dp[l+1][r- 1]这里的l和r是能找到的第一个和最后一个首尾字符所在的index. 首先乘以二的原因不变,那么为什么要减去dp[l+1][r- 1]呢?首先很明显我们不用加一也不用加二,因为原字符串里面肯定是有现在的首尾字符的,所以加进去产生不了新的类似于b, bb这种回文。然后为什么要减呢?因为我们乘以二的时候,就是在把原来所有可能的回文最外层再包上首尾字符,而因为最左最右该字符所包含的回文里面已经算了一遍内部所有的回文包上该字符所产生的新回文,那么我们再给之前的答案包上就会产生重复。举例: babacabab, 这种情况我们计算count("babacabab") = 2*count("abacaba") - count("aca"), 因为在count(“bacab”)这个串里面,我们早就算过"aca"两边包裹上bb变成“bacab"这种情况了,所以不需要重复计算。
image.png

最后是取模的计算出了一些差错,我一开始是直接dp[i][j] = (dp[i][j] + mod) % mod, 事实上是需要先判断dp[i][j]是否小于零.???

class Solution {
    
    public int countPalindromicSubsequences(String S) {
        int mod = 1000000007;
        int n = S.length();
        int[][] dp = new int[n][n];
        //substring of length 1
        for (int i = 0; i < n; i++){
            dp[i][i] = 1;
        }
        //substring with length 2 or more
        for (int len = 1; len <= n; len++){
            for (int i = 0; i < n - len; i++){
                int j = i + len;
                if (S.charAt(i) == S.charAt(j)){
                    dp[i][j] = dp[i + 1][j - 1] * 2;
                    int l = i + 1;
                    int r = j - 1;
                    while (l <= r && S.charAt(l) != S.charAt(i)){
                        l++;
                    }
                    while (l <= r && S.charAt(r) != S.charAt(i)){
                        r--;
                    }
                    if (l == r){
                        dp[i][j] += 1;
                    } else if ( l > r){
                        dp[i][j] += 2;
                    } else {
                        dp[i][j] -= dp[l + 1][r - 1];
                    }   
                } else {
                    dp[i][j] = dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1];
                }
                dp[i][j] = dp[i][j] < 0 ? dp[i][j] + mod : dp[i][j] % mod;
            }
        }
        return dp[0][n - 1];
    }
}

你可能感兴趣的:(730. Count Different Palindromic Subsequences)