摘要
本文主要介绍了LeetCode动态规划的几个题目,包括392.判断子序列、115.不同的子序列。这两道问题与编辑距离问题有关。
1、392.判断子序列
1.1 思路
解题思路
动规五部曲
- dp数组以及下标的定义:
dp[i][j]表示字符串s下标i结尾是否是字符串t下标j结尾的最长公共子序列的长度为dp[i][j]
-
递推公式:
if(s.charAt(i)==t.charAt(j) dp[i][j] = dp[i-1][j-1]) + 1
;dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1])
-
dp数组初始化
-
遍历顺序
-
打印dp数组
1.2 代码
public boolean isSubsequence(String s, String t) {
int len1 = s.length();
int len2 = t.length();
int[][] dp = new int[len1+1][len2+1];
for(int i=1; i<=len1; i++) {
for(int j=1; j<=len2; j++) {
if(s.charAt(i-1) == t.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1] + 1;
} else {
dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
}
}
}
return dp[len1][len2] == len1;
}
2、115.不同的子序列 *
2.1 思路
-
思路
- 这道题目相对于72. 编辑距离,简单了不少,因为本题相当于只有删除操作,不用考虑替换增加之类的
-
动规五部曲
-
确定dp数组(dp table)以及下标的含义
dp[i][j]
:以i-1为结尾的s子序列中出现以j-1为结尾的t的个数为dp[i][j]
-
确定递推公式
-
s[i - 1] 与 t[j - 1]相等
-
例如: s:bagg 和 t:bag
- s[3] 和 t[2]是相同的,但是字符串s也可以不用s[3]来匹配,即用s[0]s[1]s[2]组成的bag
-
dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
-
-
s[i - 1] 与 t[j - 1] 不相等
dp[i][j]
只有一部分组成,不用s[i - 1]来匹配(就是模拟在s中删除这个元素),即:dp[i - 1][j]
dp[i][j] = dp[i - 1][j]
-
-
dp数组如何初始化
-
dp[i][0]
表示:以i-1为结尾的s可以随便删除元素,出现空字符串的个数dp[i][0]
一定都是1
-
dp[0][j]
:空字符串s可以随便删除元素,出现以j-1为结尾的字符串t的个数dp[0][j]
一定都是0
-
dp[0][0]
应该是1
-
-
确定遍历顺序
- 遍历的时候一定是从上到下,从左到右
-
举例推导dp数组
-
2.2 代码
public int numDistinct(String s, String t) {
int len1 = s.length();
int len2 = t.length();
int[][] dp = new int[len1+1][len2+1];
dp[0][0] = 1;
for(int i=1; i<=len1; i++) {
dp[i][0] = 1;
for(int j=1; j<=len2; 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[len1][len2];
}