随想录训练营Day55 | DP - - 392.判断子序列, 115.不同的子序列
标签: LeetCode闯关记
392.判断子序列
class Solution {
public boolean isSubsequence(String s, String t) {
int lenS = s.length();
int lenT = t.length();
if(lenS > lenT){
return false;
}
// 初始化动态规划数组dp
// dp[i][j]表示s[0...i-1]是否为t[0...j-1]的子序列
boolean dp[][] = new boolean[lenS+1][lenT+1];
// 当t为空串时,空串不包含任何子序列,所以dp[i][0]全部赋值为false(重点)
for (int i = 1; i <= lenS; i++) {//注意dp[0][0]为true;
dp[i][0] = false;
}
// 当s为空串时,任何非空字符串都包含空子序列,所以dp[0][j]全部赋值为true
for (int j = 0; j <= lenT ; j++) {
dp[0][j] = true;
}
for (int i = 1; i <= lenS ; i++) {
for (int j = 1; j <= lenT ; j++) {
if(s.charAt(i-1) == t.charAt(j-1)){
// 如果s[i-1]等于t[j-1],那么s[0...i-1]是否为t[0...j-1]的子序列
// 取决于s[0...i-2]是否为t[0...j-2]的子序列,即dp[i-1][j-1]
dp[i][j] = dp[i-1][j-1];
}else{
// 如果s[i-1]不等于t[j-1],那么s[0...i-1]是否为t[0...j-1]的子序列
// 取决于s[0...i-1]是否为t[0...j-2]的子序列,即dp[i][j-1]
dp[i][j] = dp[i][j-1];
}
//System.out.println("i=" + i + "j=" + j + " dp[i][j]=" + dp[i][j]);
}
}
return dp[lenS][lenT];
}
}
另一种思路:int[][] —— dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为dp[i][j]。
115.不同的子序列

public int numDistinct(String s, String t) {
int lenS = s.length();
int lenT = t.length();
//dp[i][j]:以i-1为结尾的s子序列中出现以j-1为结尾的t的个数为dp[i][j]。
int[][] dp = new int[lenT+1][lenS+1]; // 注意行和列的顺序
//dp[0][i]指的是通过删除s的元素来得到空串t的方法,那么自然只有一种,即删除所有元素
//注意,dp[0][0]为1;
for (int i = 0; i <= lenT ; i++) { // 注意从0开始循环
dp[i][0] = 0;
}
//dp[i][0]表示s为空串,那么没有任何方法使得s的子序列能够=非空序列t
for (int j = 0; j <= lenS ; j++) { // 注意从0开始循环
dp[0][j] = 1;
}
for (int i = 1; i <= lenT ; i++) {
for (int j = 1; j <= lenS ; j++) {
if(s.charAt(j-1) == t.charAt(i-1)){
dp[i][j] = dp[i-1][j-1] + dp[i][j-1];//注意体会递推公式,if(s.charAt(j-1) == t.charAt(i-1)),dp[i][j]由两部分组成
}else{
dp[i][j] = dp[i][j-1];
}
}
}
return dp[lenT][lenS];
}