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