115. Distinct Subsequences

问题:

给定字符串s,匹配串t

求s中匹配t的方法有多少种。

匹配:s中存在t的序列。

Example 1:
Input: s = "rabbbit", t = "rabbit"
Output: 3
Explanation:
As shown below, there are 3 ways you can generate "rabbit" from S.
rabbbit
rabbbit
rabbbit

Example 2:
Input: s = "babgbag", t = "bag"
Output: 5
Explanation:
As shown below, there are 5 ways you can generate "bag" from S.
babgbag
babgbag
babgbag
babgbag
babgbag
 

Constraints:
1 <= s.length, t.length <= 1000
s and t consist of English letters.

  

解法:DP

1.状态:dp[i][j]:用t[0~j]去匹配s[0~i]所能匹配的方法数。

i:字符串s[0~i]

j:字符串t[0~j]

2.选择:我们将t看作固定的串

  • case_1:s[i]==t[j]:所有匹配包含两部分:SUM {
    • s[i]在匹配串里(t[j]匹配s[i]):dp[i-1][j-1] (方法数=t[0~j-1]匹配s[0~i-1]的情况个数)
    • s[i]不在匹配串里(t[j]匹配s[i]以前的字符):dp[i-1][j](方法数=t[0~j]匹配s[0~i-1]的情况个数) }
  • case_2:s[i]!=t[j]
    • s[i]不在匹配串里(t[j]匹配s[i]以前的字符):dp[i-1][j](方法数=t[0~j]匹配s[0~i-1]的情况个数)

3.base:

dp[0][j]:s="", t="XXXXX", 那么所有匹配方法数=0

dp[i][0]:s="XXXXX",t="",那么所有匹配方法数=1

4,♻️ 优化

  • dp[i][j]= dp[i-1][j-1] + dp[i-1][j]
  • dp[i][j]= dp[i-1][j]

当前格子,只与它⬆️ 上方和↖️左上方的格子相关。

去掉 i,每次保存上一行的内容,

从后向前 j=m->0,遍历,(可以防止要用的↖️左上方格子先被覆盖更新)

 

代码参考:

 1 class Solution {
 2 public:
 3     //dp[i][j]:s[0~i] t[0~j]:the number of ways of construction.
 4     //opt:(let t fixed)
 5     //s[i]==t[j]: dp[i-1][j-1] + dp[i-1][j]
 6     //    2 parts:  t[0~j-1] match s[0~i-1]: then both s&t process one step.
 7                     //(s[i] is included in subsequence)
 8     //              t[0~j] match s[0~i-1]: before s[i], already matched by fixed t
 9                     //(s[i] is excluded in subsequence)
10     //s[i]!=t[j]: dp[i-1][j]: before s[i], already matched by fixed t
11                     //(s[i] is excluded in subsequence)
12     //base:
13     //dp[0][j]:0
14     //dp[i][0]:1
15     int numDistinct(string s, string t) {
16         int n=s.length(), m=t.length();
17         vector<vector<long>>dp(n+1, vector<long>(m+1, 0));
18         for(int i=0; i<=n; i++) dp[i][0]=1;
19         for(int i=1; i<=n; i++) {
20             for(int j=1; j<=m; j++) {
21                 if(s[i-1]==t[j-1]) {
22                     dp[i][j]=dp[i-1][j-1]+dp[i-1][j];
23                 } else {
24                     dp[i][j]=dp[i-1][j];
25                 }
26             }
27         }
28         return dp[n][m];
29     }
30 };

 

♻️ 优化后:

 1 class Solution {
 2 public:
 3     //dp[i][j]:s[0~i] t[0~j]:the number of ways of construction.
 4     //opt:(let t fixed)
 5     //s[i]==t[j]: dp[i-1][j-1] + dp[i-1][j]
 6     //    2 parts:  t[0~j-1] match s[0~i-1]: then both s&t process one step.
 7                     //(s[i] is included in subsequence)
 8     //              t[0~j] match s[0~i-1]: before s[i], already matched by fixed t
 9                     //(s[i] is excluded in subsequence)
10     //s[i]!=t[j]: dp[i-1][j]: before s[i], already matched by fixed t
11                     //(s[i] is excluded in subsequence)
12     //base:
13     //dp[0][j]:0
14     //dp[i][0]:1
15     int numDistinct(string s, string t) {
16         int n=s.length(), m=t.length();
17         //vector<vector<long>>dp(n+1, vector<long>(m+1, 0));
18         vector<long>dp(m+1,0);
19         dp[0]=1;
20         //for(int i=0; i<=n; i++) dp[i][0]=1;
21         for(int i=1; i<=n; i++) {
22             for(int j=m; j>=1; j--) {
23                 if(s[i-1]==t[j-1]) {
24                     //dp[i][j]=dp[i-1][j-1]+dp[i-1][j];
25                     dp[j]=dp[j-1]+dp[j];
26                 } else {
27                     //dp[i][j]=dp[i-1][j];
28                     dp[j]=dp[j];
29                 }
30             }
31         }
32         //return dp[n][m];
33         return dp[m];
34     }
35 };

 

posted @ 2021-04-01 13:34  habibah_chang  阅读(35)  评论(0编辑  收藏  举报