LeetCode 115.不同的子序列
题目链接:115.不同的子序列
踩坑:看了视频,但还是没注意到题目要求里的取模操作,虽然说是取模,但应该是避免溢出,因此实际操作时改变数据类型即可。
思路:核心是动态数组的含义与递推公式的理解
- dp数组的含义:dp[i][j]:以i-1结尾的s中有多少个以j-1结尾的t
- 递推公式:当s[i-1] == t[j-1] 都为g时,以s = “bagg”,t = "bag"为例,有什么样的情况可以直接推导出dp[i][j]。情况1,由于后缀都相同,所以ba在bag中所有的情况可以一比一复制到bag在bagg中的情况,因此dp[i][j]中有这种情况一份。情况2,情况1中的在bag中的ba还需要添加后缀才能符合情况,同时也应该有不需要后缀也可以满足要求的,如bag(s)中的bag(t),dp[i][j]中也有这种情况一份。综上,dp[i][j] = dp[i-1][j-1] + dp[i-1][j]
- 初始化:由递推公式可知,等式依赖左上方和上方,因此需要初始化第一行,第一列,又根据dp数组的含义,第一行应初始化为0,第一列应初始化为1,(0,0)应该为1。
- 遍历顺序:从左到右,从上到下
代码:
class Solution {
public:
int numDistinct(string s, string t) {
vector<vector<uint64_t>> dp(s.size()+1, vector<uint64_t>(t.size()+1, 0));
for(int i = 0; i <= s.size(); i++) dp[i][0] = 1;
for(int j = 0; j <= t.size(); j++) dp[0][j] = 0;
dp[0][0] = 1;
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()];
}
};
LeetCode 583. 两个字符串的删除操作
题目链接:583. 两个字符串的删除操作
踩坑:看了视频,再次感叹动态规划的nb
思路:
- 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,要么删除word2,要么全删,所以dp[i][j] = min(1+dp[i-1][j], 1+dp[i][j-1], 2+dp[i-1][j-1]),第三项在逻辑上会与前两项重复,所以可以省去。
- 初始化:有递推公式可知,dp[i][j]依赖左,上,左上方。因此需要初始化第一行,第一列。同时根据题目要求与dp数组定义,dp[i][0] = i, dp[0][j] = j
- 遍历顺序:从左到右,从上到下
代码:
class Solution {
public:
int minDistance(string word1, string word2) {
vector<vector<int>> dp(word1.size()+1, vector<int>(word2.size()+1, 0));
for(int i = 0; i <= word1.size(); i++) dp[i][0] = i;
for(int j = 0; j <= word2.size(); j++) dp[0][j] = j;
for(int i = 1; i <= word1.size(); i++)
{
for(int j = 1; j <= word2.size(); j++)
{
if(word1[i-1] == word2[j-1]) dp[i][j] = dp[i-1][j-1];
else dp[i][j] = min(1 + dp[i-1][j], 1 + dp[i][j-1]);
}
}
return dp[word1.size()][word2.size()];
}
};
LeetCode 72. 编辑距离
题目链接: 72. 编辑距离
踩坑:看了视频
思路:核心是如果两个字符串想相同,仅通过删除与增加操作,所需的步骤数是一样的。而替换则是将字母替换成一样的,这样就比本就一样多出一步而已。其余都与583. 两个字符串的删除操作一样
代码:
class Solution {
public:
int minDistance(string word1, string word2) {
vector<vector<int>> dp(word1.size()+1, vector<int>(word2.size()+1, 0));
for(int i = 0; i <= word1.size(); i++) dp[i][0] = i;
for(int j = 0; j <= word2.size(); j++) dp[0][j] = j;
for(int i = 1; i <= word1.size(); i++)
{
for(int j = 1; j <= word2.size(); j++)
{
if(word1[i-1] == word2[j-1]) dp[i][j] = dp[i-1][j-1];
else dp[i][j] = min(min(dp[i-1][j] + 1, dp[i][j-1] + 1), dp[i-1][j-1] + 1);
}
}
return dp[word1.size()][word2.size()];
}
};