392.判断子序列(编辑距离问题的入门题目)
文章链接:代码随想录 (programmercarl.com)
思路:此题与最长公共子序列那题很像,思路保持一致,只不过在最后判断dp[slen][tlen]是否等于s.length(),动规五步曲
(1)确定dp数组以及含义
dp[i][j]表示字符串s在区间[0,i - 1],字符串t在区间[0,j - 1]中最长公共子序列长度为dp[i][j]
(2)确定递推公式
如果s.charAt(i - 1) 和 t.charAt(j - 1) 相等,,那么dp[i][j] = dp[i - 1][j - 1] + 1
如果两者不相等,那么dp[i][j] = Math.max(dp[i - 1][j],dp[i][j - 1] )
(3)初始化
数组默认初始化为0
(4)确定遍历顺序
从前往后,从上到下
(5)举例推导验证
看完文章后的反思:
(1)递推公式出错
if (s[i - 1] != t[j - 1]),此时相当于t要删除元素,t如果把当前元素t[j - 1]删除,那么dp[i][j] 的数值就是 看s[i - 1]与 t[j - 2]的比较结果了,即:dp[i][j] = dp[i][j - 1];
Java代码:
class Solution {
public boolean isSubsequence(String s, String t) {
int slen = s.length();
int tlen = t.length();
//(1)确定dp数组含义
//dp[i][j]表示字符串s在区间[0,i - 1],字符串t在区间[0,j - 1]中最长公共子序列长度为dp[i][j]
int[][] dp = new int[slen + 1][tlen + 1];
//(3)初始化,数组默认初始化为0
//(2)确定递推公式
//(3)确定遍历顺序
for(int i = 1;i < slen + 1;i++){
char sc = s.charAt(i - 1);
for(int j = 1; j < tlen + 1;j++){
char tc = t.charAt(j - 1);
if(sc == tc){
dp[i][j] = dp[i - 1][j - 1] + 1;
}
else{
dp[i][j] = dp[i][j - 1];
}
}
}
return dp[slen][tlen] == slen ? true:false;
}
}
115.不同的子序列(困难题)
文章链接:代码随想录 (programmercarl.com)
思路:无思路
看完文章后的反思:
(1)确定dp数组以及含义
dp[i][j]:以i-1为结尾的s子序列中出现以j-1为结尾的t的个数为dp[i][j]
(2)确定递推公式
当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]来匹配(就是模拟在s中删除这个元素),即:dp[i - 1][j]
(3)初始化
dp[i][0] 表示:以i-1为结尾的s可以随便删除元素,出现空字符串的个数,应当均为1
dp[0][j]:空字符串s可以随便删除元素,出现以j-1为结尾的字符串t的个数,应当均为0
dp[0][0]应该是1,空字符串s,可以删除0个元素,变成空字符串t
(4)确定遍历顺序
从前往后,从上到下
(5)举例推导验证
Java代码:
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()];
}
}