☆打卡算法☆LeetCode 115、 不同的子序列 算法解析
推荐阅读
大家好,我是小魔龙,Unity3D软件工程师,VR、AR,虚拟仿真方向,不定时更新软件开发技巧,生活感悟,觉得有用记得一键三连哦。
一、题目
1、算法题目
“给定一个字符串s和字符串t,计算s的子序列中t出现的个数。”
题目链接:
来源:力扣(LeetCode)
链接: 115. 不同的子序列
2、题目描述
给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。
字符串的一个 子序列 是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,“ACE” 是 “ABCDE” 的一个子序列,而 “AEC” 不是)
题目数据保证答案符合 32 位带符号整数范围。
示例 1:
输入:s = "rabbbit", t = "rabbit"
输出:3
解释:
如下所示, 有 3 种可以从 s 中得到 "rabbit" 的方案。
rabbbit
rabbbit
rabbbit
示例 2:
输入:s = "babgbag", t = "bag"
输出:5
解释:
如下所示, 有 5 种可以从 s 中得到 "bag" 的方案。
babgbag
babgbag
babgbag
babgbag
babgbag
二、解题
1、思路分析
这道题可以考虑使用动态规划的方法阶梯,假设字符串s和t的长度为m和n,要算s的子序列在t中出现的个数,那么s的长度一定大于或等于t的长度,也就是只有当m≥n的时候,个数才大于0,如果m≤n,就直接返回0。
创建二维数组dp,其中dp[i][j]表示前 t[i] 个字符可以由 s[j] 字符串组成的个数。
所以动态规划方程:
当 s[j] == t[i] , dp[i][j] = dp[i-1][j-1] + dp[i][j-1]
当s[j] != t[i] , dp[i][j] = dp[i][j-1]
通过动态方程,最终计算得到dp[0][0]即为在s的子序列中t出现的个数。
2、代码实现
代码参考:
class Solution {
public int numDistinct(String s, String t) {
int m = s.length(), n = t.length();
if (m < n) {
return 0;
}
int[][] dp = new int[m + 1][n + 1];
for (int i = 0; i <= m; i++) {
dp[i][n] = 1;
}
for (int i = m - 1; i >= 0; i--) {
char sChar = s.charAt(i);
for (int j = n - 1; j >= 0; j--) {
char tChar = t.charAt(j);
if (sChar == tChar) {
dp[i][j] = dp[i + 1][j + 1] + dp[i + 1][j];
} else {
dp[i][j] = dp[i + 1][j];
}
}
}
return dp[0][0];
}
}
3、时间复杂度
时间复杂度 : O(mn)
其中m和n分别是字符串s和t的长度,对于二维数组来说,需要对dp中每个元素进行计算。
空间复杂度: O(mn)
其中m和n分别是字符串s和t的长度。
三、总结
题解中的关键:
s[i] == t[j]的时候, s[i] 可以选择自己
是否跟 t[j]匹配
- 如果匹配,那么 dp[i][j] 其中一部分数量就是 dp[i+1][j+1]
- 如果选择不匹配(这样可以让前面的字符跟t[j]匹配,毕竟t 短的,s 长) dp[i][j] 另外一部分就是 dp[i+1][j]
所以才会有:
dp[i][j] = dp[i+1][j+1] + dp[i+1][j]
- 点赞
- 收藏
- 关注作者
评论(0)