72.编辑距离
思路
编辑距离是一个很经典的动态规划的问题,其难点在于状态的定义,在此题中,需要一个二维的dp数组,dp[i][j] 表示 s1 的前 i 个字母和 s2 的前 j 个字母之间的编辑距离。
而状态转移方程的确定,也需要分情况谈论:
1. 当s1[i-1]==s2[j-1],因为下标从0开始,所以实际上是s1的第i个字符和s2的第j个字符相等,那么此时这两个字符不需要变换,所以 dp[i][j]=dp[i-1][j-1];
2. 当s1[i-1]!=s2[j-1],也就是s1的第i个字符和s2的第j个字符不相等,那么有三种做法:
- 将s1的前i-1个字符编辑成s2的前j个,再把s1的第i个字符删除
- 将s1的前i个字符编辑成s2的前j-1个,再添加一个和s2[j]一样的字符
- 将s1的前i-1个字符编辑成s2的前j-1个,再将s1[i]替换成s2[j]
所以,就有了状态转移方程:
dp[i][j] = min(min(dp[i-1][j] + 1, dp[i][j-1] + 1), dp[i-1][j-1] + 1)
代码
class Solution {
public:
int minDistance(string s1, string s2) {
int m = s1.size();
int n = s2.size();
int dp[m+1][n+1];
for (int i = 0; i < m+1; i++) dp[i][0] = i;
for (int i = 0; i < n+1; i++) dp[0][i] = i;
for (int i = 1; i < m+1; i++){
for (int j = 1; j < n+1; j++){
if (s1[i-1] == s2[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[m][n];
}
};
75.颜色分类
思路
此题也是一个经典题目,称为荷兰国旗问题
我们用三个指针(p0, p2 和curr)来分别追踪0的最右边界,2的最左边界和当前考虑的元素。
While cur <= p2 :
若 nums[cur] = 0 :交换第 curr个 和 第p0个 元素,并将指针都向右移
若 nums[cur] = 2 :交换第 curr个和第 p2个元素,并将 p2指针左移
若 nums[cur] = 1 :将指针curr右移
这里有一个容易疏忽的细节,就是当nums[cur]==2的时候,交换位置以后,cur是不自增的,因为p2位置上的元素还是没有检查过的,而由于p0始终在cur左边或者等于cur,所以当nums[cur]==0,交换位置时,p0的位置已经被cur检查过了,只能是0或者1,因此交换以后cur直接自增。
代码
class Solution {
public:
void sortColors(vector<int>& nums) {
int p0=0,p2=nums.size()-1;
int cur=0;
while(cur<=p2){
if(nums[cur]==2)
//这里的cur还没有检查过,不能自增
swap(nums[cur],nums[p2--]);
else if(nums[cur]==0)
swap(nums[cur++],nums[p0++]);
else
cur++;
}
}
};
76.最小覆盖子串
思路
这道题是这些天来遇到的比较难的一道,要用到滑动窗口的思想,详见大佬的题解
代码
class Solution {
public:
string minWindow(string s, string t) {
// 记录最短子串的开始位置和长度
int start = 0, minLen = INT_MAX;
int left = 0, right = 0;
unordered_map<char, int> window;
unordered_map<char, int> needs;
for (char c : t) needs[c]++;
int match = 0;
while (right < s.size()) {
char c1 = s[right];
//count方法,如果有返回1,否则返回0
if (needs.count(c1)) {
window[c1]++;
if (window[c1] == needs[c1])
match++;
}
right++;
while (match == needs.size()) {
if (right - left < minLen) {
// 更新最小子串的位置和长度
start = left;
minLen = right - left;
}
char c2 = s[left];
if (needs.count(c2)) {
window[c2]--;
if (window[c2] < needs[c2])
match--;
}
left++;
}
}
return minLen == INT_MAX ?
"" : s.substr(start, minLen);
}
};