代码随想录|392.判断子序列,115.不同的子序列(需要二刷)

392.判断子序列

先用双指针做 

class Solution {
    public boolean isSubsequence(String s, String t) {

        //双指针
        int m=s.length();
        int n=t.length();
        int slow=0;
        int i=0;int j=0;
        while(i

再用动规

1.确定dp数组(dp table)以及下标的含义

dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为dp[i][j]。注意要判断s是否为t的子序列。即t的长度是大于等于s的

2.确定递推公式

if (s[i - 1] == t[j - 1]),那么dp[i][j] = dp[i - 1][j - 1] + 1;,因为找到了一个相同的字符

if (s[i - 1] != t[j - 1]),此时相当于t要删除元素,t如果把当前元素t[j - 1]删除,那么dp[i][j] 的数值就是 看s[i - 1]与 t[j - 2]的比较结果了,即:dp[i][j] = dp[i][j - 1];

3.dp初始化

dp[i][j]都是依赖于dp[i - 1][j - 1] 和 dp[i][j - 1],dp[0][0]表示两个空字符串相同子序列的长度,dp[i][0]表示下标为i-1的字符串s与空字符串t的相同子序列的长度,所以dp[0][0],dp[i][0]都初始化为0

4.遍历顺序

根据递推公式可知是从前往后的

5.推导dp

代码随想录|392.判断子序列,115.不同的子序列(需要二刷)_第1张图片

代码实现 

class Solution {
    public boolean isSubsequence(String s, String t) {
        //动规
        int m=s.length();
        int n=t.length();
        int[][] dp=new int[m+1][n+1];
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                if(s.charAt(i-1)==t.charAt(j-1)){//比较的是下标i-1和j-1对应的字符
                    dp[i][j]=dp[i-1][j-1]+1;
                }
                else{
                     dp[i][j]=dp[i][j-1];
                }
            }
        }
        return dp[m][n]==m?true:false;
    }
}

115.不同的子序列(需要二刷)

这里要明确,我们要求的是s中有多少个t

1.确定dp数组(dp table)以及下标的含义

dp[i][j]:以i-1为结尾的s子序列中出现以j-1为结尾的t的个数为dp[i][j]。

2.确定递推公式

当s[i - 1] 与 t[j - 1]相等时,dp[i][j]可以有两部分组成。

一部分是用s[i - 1]来匹配,那么个数为dp[i - 1][j - 1]。一部分是不用s[i - 1]来匹配,个数为dp[i - 1][j]。例如: s:bagg 和 t:bag ,s[3] 和 t[2]是相同的,但是字符串s也可以不用s[3]来匹配,即用s[0]s[1]s[2]组成的bag。当然也可以用s[3]来匹配,即:s[0]s[1]s[3]组成的bag。

所以当s[i - 1] 与 t[j - 1]相等时,dp[i][j]=dp[i-1][j-1]+dp[i-1][j];

当s[i-1]与t[j-1]不相等时,s中只要一部分能组成t,不用s[i-1]来匹配(就是模拟在s中删除这个元素即:dp[i-1][j])所以递推公式:dp[i][j]=dp[i-1][j]

3.dp初始化

从递推公式dp[i][j]=dp[i-1][j]和dp[i][j]=dp[i-1][j-1]+dp[i-1][j]来看,dp[0][0]应该是1,空字符串s,可以删除0个元素,变成空字符串t。,dp[i][0]表示以i-1为结尾的字符串s中能匹配出多少个空字符串t,所以dp[i][0]一定都是1,因为也就是把以i-1为结尾的s,删除所有元素,出现空字符串的个数就是1;dp[0][j]表示空字符串s能匹配出以j-1为结尾的字符串t的个数,所以dp[0][j]一定都是0,s如论如何也变成不了t。

4.遍历顺序从前往后

5.推导dp

代码随想录|392.判断子序列,115.不同的子序列(需要二刷)_第2张图片

代码实现

class Solution {
    public int numDistinct(String s, String t) {
        int m=s.length();
        int n=t.length();
        int[][] dp=new int[m+1][n+1];
        //初始化
        
        for(int i=0;i<=m;i++){dp[i][0]=1;}
        // for (int j = 1; j < t.size(); j++) dp[0][j] = 0; //默认就是初始化为0
        //递推
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                if(s.charAt(i-1)==t.charAt(j-1)){
                    dp[i][j]=dp[i-1][j-1]+dp[i-1][j]; //如s=bagg,t=bag

                }
                else{
                    dp[i][j]=dp[i-1][j];//
                }
            }
        }
        return dp[m][n];

    }
}

你可能感兴趣的:(算法训练营,算法,leetcode,数据结构)