115. Distinct Subsequences

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.


题意:给定2个字符串S和T。将字符串S删除若干个字符之后(可以为0个)得到字符串T,请问共有多少种删除方式?


这个题的第一想法是使用递归,事实上也是最容易想到的解题方法,下面介绍递归解法以及将其转化成动态规划的解法

1、递归解法(此方法在LeetCode上运行会超时,仅作为参考以及第二解法的过渡)

核心思想:遍历字符串S的每个字符,当S中某个字符与字符串T的首字符相同时,递归调用方法numDistinct(s.substring(k),t.substring(1)),其中k表示S中下标为k 的字符与字符串T的首字符相同,最后将每次递归调用返回的值相加,就得到最终结果。

下面贴代码:

public class Solution {
    public int numDistinct(String s, String t) {
        if(s.length()<t.length()) return 0;
        if(s.length()==t.length()){
            if(s.equals(t)) return 1;
            else return 0;
        }
        if(t.equals("")) return 1;
        int num = 0;
        for(int i=0;i<=s.length()-t.length();i++){
             if(s.charAt(i) == t.charAt(0))
               num += numDistinct(s.substring(i+1),t.substring(1));
              
        }
        return num;
    }
}
2、 动态规划解法

我们定义一个数组a[s.length+1][t.length+1]

其中a[i][j]表示:

s1:字符串S从下标为i开始到末尾的子串;

 t1:字符串T从下标为j开始到末尾的子串;

a[i][j]表示字符串s1删除若干字符后得到t1总共有多少种删除方式。

那么a[0][0]即是题目要求的结果。

仔细观察我们可以看到这样一个规律,对于每一个a[i][j],有以下2种情况:

1.如果S下标为i的字符等于T下标为j的字符,那么a[i][j] = a[i+1][j+1] + a[i+1][j];

2.如果S下标为i的字符不等于T下标为j的字符,那么a[i][j] = a[i+1][j];

有了以上推倒规律之后,我们再来考虑初始条件,事实上初始条件即为0

下面是动态规划解法的代码:

public class Solution {
    public int numDistinct(String s, String t) {
        if(s.length()<t.length()) return 0;
        if(s.length()==t.length()){
            if(s.equals(t)) return 1;
            else return 0;
        }
        if(t.equals("")) return 1;
        int[][] a = new int[s.length()+1][t.length()+1];
        a[s.length()][t.length()-1] = 0;
        for(int i=s.length()-1;i>=0;i--){
            if(s.charAt(i)==t.charAt(t.length()-1))
            a[i][t.length()-1]=a[i+1][t.length()-1]+1;
            else a[i][t.length()-1]=a[i+1][t.length()-1];
        }
        for(int j=t.length()-2;j>=0;j--){
            for(int i=s.length()+j-t.length();i>=0;i--){
                if(s.charAt(i)==t.charAt(j)){
                    a[i][j] = a[i+1][j+1] + a[i+1][j];
                }else{
                    a[i][j] =  a[i+1][j];
                }
            }
        }
        return a[0][0];
    }
}

此类题目用动态规划解决是一种很好的方法,但是状态转移方程不易寻找,我们可以从递归解法中寻找规律,找到 状态转移方程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值