剑指 Offer II 097. 子序列的数目

class Solution {
    public int numDistinct(String s, String t) {
        int m = s.length(), n = t.length();
        if (m < n) {
            return 0;
        }
        int[][] dp = new int[n + 1][m + 1];
        for (int i = 0; i <= m; i++) {
            dp[0][i] = 1;
        }
        for (int i = 1; i <=n; i++) {
            char tChar = t.charAt(i-1);
            for (int j = 1; j <=m; j++) {
                char sChar = s.charAt(j-1);
                if (sChar == tChar) {
                    dp[i][j] = dp[i - 1][j - 1] + dp[i][j-1];
                } else {
                    dp[i][j] = dp[i][j-1];
                }
            }
        }
        return dp[n][m];
    }
}

核心点:转移方程

if (sChar == tChar) {
     dp[i][j] = dp[i - 1][j - 1] + dp[i][j-1];
} else {
     dp[i][j] = dp[i][j-1];

dp[i][j]表示s的前j部分的子序列在t的前i部分出现的次数。

对于dp[i][j]情况时,如果s和t的结尾相同即sChar == tChar,要想计算出t[i]出现次数,考虑两种情况。
其一: s[j-1]中有没有t[j-1],这个t[i-1]是我们当前要找的t[i]的前缀,
	   因为sChar==tChar所以t[i-1]+ sChar就是t[i]了。这对应着dp[i - 1][j - 1]
其二: 我们在第一种情况中,主要寻找前缀,因为前缀加上s[j]的结尾就是我们要找的t[i]。
		在第二种情况我们就寻找s[j-1]中有没有t[i](不需要考虑最后一个字母是否相等)。
		这种情况对应dp[i][j-1]
因此 当sChar == tChar,将两种情况的个数相加就行,
也就是能和最后一个新添加的字母组成t[i]的前缀个数+在s[j-1]中以及出现过的t[i]的个数。
总的状态转移方程为: dp[i][j] = dp[i - 1][j - 1] + dp[i][j-1];


而当sChar != tChar时,也就是 结尾新添加的字母不同时,s[j-1]的前缀即便加上结尾字母也不等于t[i],我们就是能寻找s[j-1]中以及出现的t[i],他就对应上面的情况二:dp[i][j-1]
因此这时的状态转移方程为: dp[i][j-1]

边界条件怎么生成可以从代码中看出。

如果是 t[0] ,也就是空串,当然有且只有一个子序列也就是空序列了。

而如果是 s[0],它本身是空串,而 i > 0 ,无论如何也找不出子序列了,因为 s 长度都已经 t 了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值