LeetCode 115 不同的子序列
思路
给你两个字符串 s 和 t ,统计并返回在 s 的 子序列 中 t 出现的个数,结果需要对 取模。
示例:
输入:s = "rabbbit", t = "rabbit"
输出:3
解释:
如下所示, 有 3 种可以从 s 中得到 "rabbit" 的方案。
rabbbit
^^^^ ^^
rabbbit
^^^ ^^^
rabbbit
^^ ^^^^
本题仍然只需要考虑一种编辑——删除(从s中删除若干字符得到t)
考虑动态规划五部曲:
- dp数组及其下标的含义:
dp[i][j]表示在以s[i-1]结尾的子序列中以t[j-1]结尾的出现的个数。 - 确定递推公式:
- 如果
s[i-1]==t[j-1]。一部份结果使用s[i-1]和t[j-1]的匹配,那么匹配的种类就是dp[i-1][j-1],一部份不使用这个匹配,那么匹配的种类就是dp[i-1][j]。所以dp[i][j] = dp[i-1][j-1] + dp[i-1][j] - 如果
s[i-1]!=t[j-1]。一定没法使用s[i-1],所以只能用前面的匹配,即dp[i-1][j]
- 如果
- dp数组如何初始化:
dp[i][0]表示以s[i-1]结尾的字符串通过删除字符,出现空串的个数。那么我们只能删除所有字符,所以初始化为1dp[0][j]表示空串通过删除字符,出现以t[j-1](j≥1)结尾的t的个数,显然0dp[0][0]表示空串通过删除字符出现空串的个数。只有一种动作就是不删除。所以是1
- 确定遍历顺序:i从小到大遍历,j从小到大遍历。
- 举例推导dp数组
解法
class Solution {
public int numDistinct(String s, String t) {
int[][] dp = new int[s.length()+1][t.length()+1];
// 初始化dp数组
for (int i = 0; i <= s.length(); i++) {
dp[i][0] = 1;
}
for (int i = 1; i <= t.length(); i++) {
dp[0][i] = 0;
}
// 递推
for (int i = 1; i <= s.length(); i++) {
for (int j = 1; j <= t.length(); 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()];
}
}
LeetCode 583 两个字符串的删除操作
思路
给定两个单词 word1 和 word2 ,返回使得 word1 和 word2 相同所需的最小步数。
每步 可以删除任意一个字符串中的一个字符。
本题实质上就是找两个字符串的最长子序列,找到了最长子序列的长度也就能计算出删除的次数。作为编辑距离题目,编辑操作也只有删除,比较简单。
考虑动态规划五部曲:
- dp数组及其下标含义:
dp[i][j]表示以i-1结尾的word1和以j-1结尾的word2所拥有的最长子序列的长度 - 确定递推公式:
if(word1[i-1] == word2[j-1]) dp[i][j] = dp[i-1][j-1] + 1否则,dp[i][j] = max(dp[i-1][j], dp[i][j-1]) - dp数组如何初始化:
dp[i][0]和dp[0][j]都初始化为0 - 确定遍历顺序:从上到下,从左到右遍历
- 举例推导dp数组
解法
class Solution {
public int minDistance(String word1, String word2) {
int[][] dp = new int[word1.length()+1][word2.length()+1];
for (int i = 0; i <= word1.length(); i++) {
dp[i][0] = 0;
}
for (int i = 0; i <= word2.length(); i++) {
dp[0][i] = 0;
}
for (int i = 1; i <= word1.length(); i++) {
for (int j = 1; j <= word2.length(); j++) {
if (word1.charAt(i-1) == word2.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 word1.length() + word2.length() - dp[word1.length()][word2.length()] * 2;
}
}
LeetCode 72 编辑距离
思路
给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
- 插入一个字符
- 删除一个字符
- 替换一个字符
考虑动态规划五部曲:
- dp数组及其下标的含义:
dp[i][j]表示把以i-1结尾的word1转换为以j-1结尾的word2所使用的最少操作数 - 确定递推公式:先分为以下两种大情况
word1[i-1]==word2[j-1],说明新增的一对字符不需要操作,dp[i][j]=dp[i-1][j-1]word1[i-1]!=word2[j-1],对三种编辑操作讨论,取最小值- 如果把
word1[i-1]直接替换成word2[j-1],说明需要i-1这个位置和j-1匹配,所以dp[i][j] = 1 + dp[i-1][j-1] - 如果把
word1[i-1]直接删除,说明j-1可以经过操作和word1[i-1]之前的字符匹配,所以dp[i][j] = 1 + dp[i-1][j] - 如果是在
word1[i-1]后插入word2[j-1],说明word1[i]之前的字符已经和word2[j-2]匹配。所以dp[i][j] = 1 + dp[i][j-1]
- 如果把
- dp数组如何初始化:根据数组定义和递推公式,我们需要初始化任一索引为0的元素
dp[i][0]:表示把以i-1结尾的word1转换成空串需要的操作数,只需要删除所有字符。所以初始化为idp[0][j]:表示把空串转换成以j-1结尾的word2需要的操作数,只需要添加所有字符。所以初始化为j
- 确定遍历顺序:根据递推公式,一个元素以赖于其上、左、斜上方的元素,座椅从左到右从上到下遍历
- 举例推导dp数组
解法
class Solution {
public int minDistance(String word1, String word2) {
int[][] dp = new int[word1.length()+1][word2.length()+1];
for (int i = 0; i <= word1.length(); i++) {
dp[i][0] = i;
}
for (int i = 0; i <= word2.length(); i++) {
dp[0][i] = i;
}
for (int i = 1; i <= word1.length(); i++) {
for (int j = 1; j <= word2.length(); j++) {
if (word1.charAt(i-1) == word2.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1];
}
else {
dp[i][j] = Math.min(dp[i][j-1], dp[i-1][j]);
dp[i][j] = Math.min(dp[i][j], dp[i-1][j-1]);
dp[i][j]++;
}
}
}
return dp[word1.length()][word2.length()];
}
}
编辑距离总结
入门:判断子序列
给定字符串 s 和 t ,判断 s 是否为 t 的子序列。 用编辑距离的定义考虑,就是把t删除为s,编辑距离是否等于s和t的长度之差
- 定义数组:子序列长度(可以和编辑距离等价转换)
- 递推思路:讨论
s[i-1]与t[j-1]是否相同,不相同只能让t删除字符
初级:不同的子序列
给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。 用编辑距离的定义考虑,就是把s删除成t,有几种编辑方法(几种向量编辑距离)
- 定义数组:子序列个数
- 递推思路:讨论
s[i-1]与t[j-1]是否相同,相同时s[i-1]可以匹配也可以不匹配,不同时只能不匹配
中级:两个字符串的删除操作
给定两个单词 word1 和 word2,找到使得 word1 和 word2 相同所需的最少步数,每步可以删除任意一个字符串中的一个字符。
- 定义:子序列长度(可以和编辑距离等价转换)
- 递推思路:讨论
word1[i-1]与word2[j-1]是否相同,相同时一定匹配,不同时最多使用一个
终极:编辑距离
给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。操作可以是增删改。
- 定义:编辑距离
- 递推思路:讨论
word1[i-1]与word2[j-1]是否相同,相同时匹配,不同时讨论三种操作
今日收获总结
今日学习三小时。总结就是对编辑距离的总结啦。