2021.3.17
https://leetcode-cn.com/problems/distinct-subsequences/
题目
给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。
字符串的一个 子序列 是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,”ACE” 是 “ABCDE” 的一个子序列,而 “AEC” 不是)
题目数据保证答案符合 32 位带符号整数范围。
输入:s = "rabbbit", t = "rabbit"输出:3解释:如下图所示, 有 3 种可以从 s 中得到 "rabbit" 的方案。(上箭头符号 ^ 表示选取的字母)rabbbit^^^^ ^^rabbbit^^ ^^^^rabbbit^^^ ^^^输入:s = "babgbag", t = "bag"输出:5解释:如下图所示, 有 5 种可以从 s 中得到 "bag" 的方案。(上箭头符号 ^ 表示选取的字母)babgbag^^ ^babgbag^^ ^babgbag^ ^^babgbag^ ^^babgbag^^^
提示:
0 <= s.length, t.length <= 1000-
思路
知道是动态规划,没想出来,看的官方题解,给的是倒推的方程,理解后写了正推的版本,比倒推快一点。
dp[i][j] 表示s以i结尾的字符串中包含t以j结尾的字符串的个数
当 s[i] == t[j] 时 s[i]和t[j]匹配,此时个数有 dp[i - 1][j - 1]个
- s[i]不和t[j]匹配,此时个数有 dp[i - 1][j] 个
- 所以 dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]
当 s[i] != t[j]时,只有用S前面的字符串去计算
- 所以dp[i][j] = dp[i - 1][j]
**
具体推导图如上所示。两个注意点
- 如果t是空字符串,那么所有的dp[0-n][0] = 1
- 如果s是空字符串,那么所有的dp[0][1-m] = 0
-
AC代码
* 正推版本,比倒推快 * 执行用时:4 ms, 在所有 Java 提交中击败了82.62%的用户 * 内存消耗:36.7 MB, 在所有 Java 提交中击败了71.39%的用户 * @param s * @param t * @return */ public int numDistinct2(String s, String t) { int n = s.length(); int m = t.length(); if (n < m) { return 0; } int[][] f = new int[n + 1][m + 1]; for (int i = 0; i <= n ; i++) { f[i][0] = 1; } for (int i = 1; i <= m; i++) { f[0][i] = 0; } for (int i = 1; i <= n ; i++) { for (int j = 1; j <= m; j++) { f[i][j] = f[i - 1][j]; if (s.charAt(i - 1) == t.charAt(j - 1)) { f[i][j] += f[i -1][j - 1]; } } } return f[n][m]; }
