115. Distinct Subsequences

来源:互联网 发布:淘宝开店不交保证金 编辑:程序博客网 时间:2024/05/29 08:57

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];    }}

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

原创粉丝点击