leetcode——Distinct Subsequences

本文介绍了一种算法,用于计算一个字符串作为另一个字符串的子序列出现的次数。通过构建矩阵逐步匹配,实现对复杂字符串匹配问题的有效解决。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

Given a string S and a string T, count the number of distinct subsequences of T in S.

A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ACE" is a subsequence of "ABCDE" while "AEC" is not).

Here is an example:
S = "rabbbit"T = "rabbit"

Return 3.

思路:

首先,S是主串,T是匹配串,我们需要使用T的每一个字母去匹配S中的子串,而且相对位置顺序要跟T一致。

因此,我们建立矩阵,依次标明S和T的匹配情况。以题目中 的例子来看:

初始矩阵为:

 rabbbit
r       
a       
b       
b       
i       
t       
然后思考,既然有匹配时候的先后顺序,也就是T中在前的字母会先跟S进行匹配,因此,该矩阵的值(先不管值的意义),一定可以按照行的顺序先后得到。

再次,对于T的某一个字母x,如果S中有多个x可以匹配,必然是先跟S前面的x相匹配,那么,该矩阵的列的计算顺序也就是从前往后。

现在思考矩阵(设为W)值的意义:

不妨设当前位置为W[i][j],即t[i] 要跟S[j]相匹配,则有两种情况:

1.T[i] !=S[j];表示目前为止匹配到T[i]时的情况总数,其结果为上一层的结果,那么当前是W[i][j],在利用上一层的结果时,最好利用W[i-1][j-1]来记录。

2.T[i]==S[j];表示当前位置匹配到T[i]时的情况总数,其结果为上一层的结果数*1(1 为当前T[i]=S[j]这个情况)+ 当前层T[i]跟S[j]之前匹配到的情况总数。

因此,对于情况2来说,在每一层都需要初始化一个sum变量,记录截止到T[i]跟S[j]进行匹配之前的总的结果数,然后更新sum,并赋值给W[i][j]。

对于1的情况而言,每次将sum值直接赋给W[i][j]就好了。

这种处理方法的巧妙地方就在于:

对于W[i][j]而言,在对应的两个字母匹配之前的字母匹配情况都可以直接由W[i-1][j-1]得出从而直接算出当前两个字母匹配(或不匹配)之后的结果,

作为后面字母的“垫脚石”。

更具体的谈:上述矩阵计算步骤为:从上到下,从左到右。



 rabbbit
rsum=0->sum+1-> (sum=1)sum=1->1-> (sum=1)sum=1->1-> (sum=1)sum=1->1-> (sum=1)sum=1->1-> (sum=1)sum=1->1-> (sum=1)sum=1->1-> (sum=1)
asum=1->0->
(sum=1)
sum=0->1*1
(sum=1)
sum=1->1
(sum=1)
sum=1->1
(sum=1)
sum=1->1
(sum=1)
sum=1->1
(sum=1)
sum=1->1
(sum=1)
bsum=0->0
(sum=0)
sum=0->0
(sum=0)
sum=0->1*1
(sum=1)
sum=1->
sum+1*1
(sum=2)
sum=2->
sum+1*1
(sum=3)
sum=3->
3
(sum=3)
sum=3->
3
(sum=3)
b000+0*1=00+1*1=11+2*1=333
i000000+3*1=33
t0000000+3*1=3

最终在W[5][6]得到答案。


AC代码:

public class Distinct_Subsequences {
    public int numDistinct(String S, String T) {
        if(S.length()==0 && T.length()==0)
            return 1;
        if(S.length()==0 || T.length()==0)
            return 0;
        char[] s = S.toCharArray();
        char[] t = T.toCharArray();
        int[][] w = new int[t.length][s.length];
        int sum = 0;
        for(int i=0;i<s.length;i++){
            if(t[0]==s[i]){
                sum++;
                w[0][i] = sum;
            } else
                w[0][i] = sum;
        }

        for(int i=1;i<t.length;i++)
            w[i][0]=0;
        for(int i=1;i<t.length;i++){
            sum=0;
            for(int j=1;j<s.length;j++){
                if(t[i]==s[j]){
                    sum+=w[i-1][j-1];
                    w[i][j] = sum;
                }
                else
                    w[i][j]=sum;
            }
        }

        return w[t.length-1][s.length-1];
    }
    public static void main(String[] args){
        Distinct_Subsequences distinct_subsequences  = new Distinct_Subsequences();
        System.out.println(distinct_subsequences.numDistinct("r",""));
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值