leetcode 730题 区间dp解法带详细注释

区间dp + 去重
看人家的题解 自己写了下注释
题目链接

public class Solution730 {
    public int countPalindromicSubsequences(String s) {
        int n = s.length();
        int[][] dp = new int[n][n]; // dp[i][j]表示[i,j]下标范围内的回文子序列数量
        char[] ch = s.toCharArray();
        for (int i = 0; i < n; i++) {
            dp[i][i] = 1;
        }
        for (int len = 2; len <= n; len++) { //长度从2开始
            for (int i = 0; i < n - len + 1; i++) {
                int j = i + len - 1;
                if (ch[i] != ch[j]) {
                    dp[i][j] = dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1]; // 两个子区间的dp值减去重复计算后的dp值
                } else {
                    dp[i][j] = dp[i + 1][j - 1] * 2; //两端重复数相当于子串的回文数 * 2
                    /*
                    例:  b......b 中......的子序列为{x}
                    那么 b{x}b    也是回文串 所以乘2
                     */

                    //去重及增加回文串
                    int l = i + 1, r = j - 1;
                    while (l <= r && ch[l] != ch[i]) l += 1;
                    while (l <= r && ch[r] != ch[i]) r -= 1;

                    if (l > r) dp[i][j] += 2;
                    /*  例"b.....b"

                        因为l 和 r 只有遇到端点值才会停下  如果l > r 说明 子区间中无端点值
                        当 除端点外的子区间[.....] 中没有端点值时 增加b 和 bb两种回文序列

                     */
                    else if (l == r) dp[i][j] += 1;
                    /*  例:"b[..b..]b"
                        因为l 和 r 只有遇到端点值才会停下 如果l = r
                        证明除端点外的子区间中[..b..]  仅含有一个端点值且在最中间(如果含有两个及以上,l和r必定停在不同位置)

                        因为单个的端点值b已经出现过,无法增加。所以只能增加bb,因此 + 1

                     */
                    else dp[i][j] -= dp[l + 1][r - 1];
                    /*
                        例b1..b2[...]b2..b1  因为l 和 r  只有遇到端点才会停下

                        如果l < r 则当 除端点之外的子区间中..b[...]b.. 中至少含有两个端点值
                        此时考虑子区间[...]的回文子序列为{x}, 则b1 + {x} + b1 和b2 + {x} + b2组成的子序列其实是一样的
                        我们在乘算的时候就多考虑了这一部分序列 所以要减去[...]的子序列数

                        且b 和 bb 都在子序列b2[...]b2中出现过了 也就没必要加上去

                     */
                }
                dp[i][j] = dp[i][j] < 0 ? dp[i][j] + 1000000007 : dp[i][j] % 1000000007;
            }
        }
        return dp[0][n - 1];
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值