这篇page是针对leetcode上的115.不同子序列所写的。小尼先简单的说明一下这道题的意思,就是给定一个字符串s和一个字符串t,计算在s的子序列中t出现大的个数。
字符串的一个子序列是指,通过删除一些字符且不干扰剩余字符相对位置所组成的新字符串。
小尼接下来说明一下动态规划五部曲:
1.确定dp数组(dp table)以及下标的含义:dp[i][j]:以i-1为结尾的s子序列中出现以j-1为结尾的t的个数为dp[i][j]。
2.确定递推公式:这一类问题,基本是要分析两种情况
当s[i - 1] 与 t[j - 1]相等时,dp[i][j]可以有两部分组成。
一部分是用s[i - 1]来匹配,那么个数为dp[i - 1][j - 1]。
一部分是不用s[i - 1]来匹配,个数为dp[i - 1][j]。
这里可能有同学不明白了,为什么还要考虑 不用s[i - 1]来匹配,都相同了指定要匹配啊。
例如: s:bagg 和 t:bag ,s[3] 和 t[2]是相同的,但是字符串s也可以不用s[3]来匹配,即用s[0]s[1]s[2]组成的bag。
当然也可以用s[3]来匹配,即:s[0]s[1]s[3]组成的bag。
所以当s[i - 1] 与 t[j - 1]相等时,dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
当s[i - 1] 与 t[j - 1]不相等时,dp[i][j]只有一部分组成,不用s[i - 1]来匹配,即:dp[i - 1][j]
所以递推公式为:dp[i][j] = dp[i - 1][j];
3.dp数组如何初始化:从递推公式dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]; 和 dp[i][j] = dp[i - 1][j]; 中可以看出dp[i][0] 和dp[0][j]是一定要初始化的。那么初始直接就是dp[i][0]=i,dp[0][j]=j
4.确定遍历顺序:就是直接设置两层for循环进行对应的遍历
5.导出dp数组
小尼接下来拉一下这道题的代码:
- class Solution {
- public int numDistinct(String s, String t) {
- int[][] dp = new int[s.length() + 1][t.length() + 1];
- for (int i = 0; i < s.length() + 1; i++) {
- dp[i][0] = 1;
- }
-
- for (int i = 1; i < s.length() + 1; i++) {
- for (int j = 1; j < t.length() + 1; j++) {
- if (s.charAt(i - 1) == t.charAt(j - 1)) {
- dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
- }else{
- dp[i][j] = dp[i - 1][j];
- }
- }
- }
-
- return dp[s.length()][t.length()];
- }
- }
希望上面的代码可以帮助到小伙伴们~~~