代码随想录训练营打卡Day45| 动态规划part12
115.不同的子序列
题目链接:115.不同的子序列
给你两个字符串
s和t,统计并返回在s的 子序列 中t出现的个数。测试用例保证结果在 32 位有符号整数范围内。
思路:难度困难;dp[i][j]:以i-1为结尾的s子序列中出现以j-1为结尾的t的个数为dp[i][j];
这一类问题,基本是要分析两种情况
- s[i - 1] 与 t[j - 1]相等
- s[i - 1] 与 t[j - 1] 不相等
当s[i - 1] 与 t[j - 1]相等时,dp[i][j]可以有两部分组成。
一部分是用s[i - 1]来匹配,那么个数为dp[i - 1][j - 1]。即不需要考虑当前s子串和t子串的最后一位字母,所以只需要 dp[i-1][j-1],s 的前 i−1 个字符必须去构成 t 的前 j−1 个字符
一部分是不用s[i - 1]来匹配,个数为dp[i - 1][j],s 的前 i−1 个字符仍然要构成 t 的前 j 个字符
class Solution {
public:int numDistinct(string s, string t) {vector<vector<uint64_t>> dp(s.size() + 1, vector<uint64_t>(t.size() + 1));for (int i = 0; i < s.size(); i++) dp[i][0] = 1;// 用 s 的前 i 个字符,要形成 t 的前 0 个字符(空串),只有 1 种方式:什么都不选。for (int j = 1; j < t.size(); j++) dp[0][j] = 0;// 用 s 的前 0 个字符(空串),要形成 t 的前 j 个字符(非空),不可能做到 → 0 种方式。for (int i = 1; i <= s.size(); i++) {for (int j = 1; j <= t.size(); j++) {if (s[i - 1] == t[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.size()][t.size()];}
};
583. 两个字符串的删除操作
题目链接:583. 两个字符串的删除操作
给定两个单词
word1和word2,返回使得word1和word2相同所需的最小步数。每步 可以删除任意一个字符串中的一个字符。
思路:从word1变为word2 --> word1和word2变成最大公共 需要的步数;
dp[i][j] 的定义是:
用 word1 的前 i 个字符、word2 的前 j 个字符
要变成相同的字符串
需要删除字符的最小次数。
情况一:删word1[i - 1],最少操作次数为dp[i - 1][j] + 1
情况二:删word2[j - 1],最少操作次数为dp[i][j - 1] + 1
情况三:同时删word1[i - 1]和word2[j - 1],操作的最少次数为dp[i - 1][j - 1] + 2
72. 编辑距离
题目链接:72. 编辑距离
给你两个单词
word1和word2, 请返回将word1转换成word2所使用的最少操作数 。你可以对一个单词进行如下三种操作:
- 插入一个字符
- 删除一个字符
- 替换一个字符
思路:编辑距离是用动规来解决的经典题目;
dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]。
if (word1[i - 1] != word2[j - 1]),此时就需要编辑了,如何编辑呢?
- 操作一:word1删除一个元素,那么就是以下标i - 2为结尾的word1 与 j-1为结尾的word2的最近编辑距离 再加上一个操作。
即
dp[i][j] = dp[i - 1][j] + 1;
- 操作二:word2删除一个元素,那么就是以下标i - 1为结尾的word1 与 j-2为结尾的word2的最近编辑距离 再加上一个操作。
即
dp[i][j] = dp[i][j - 1] + 1;
- 操作三:替换元素,
word1替换word1[i - 1],使其与word2[j - 1]相同,此时不用增删加元素。可以回顾一下,
if (word1[i - 1] == word2[j - 1])的时候我们的操作 是dp[i][j] = dp[i - 1][j - 1]对吧。那么只需要一次替换的操作,就可以让 word1[i - 1] 和 word2[j - 1] 相同。
所以
dp[i][j] = dp[i - 1][j - 1] + 1;综上,当
if (word1[i - 1] != word2[j - 1])时取最小的,即:dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1;
