leetcode76.最小覆盖子串(困难)
作者:互联网
双指针经典题目,可以看一下leetcode.209
自己的思路:
记录出s中每个字符后面该字符的位置,当left指针移动之后,导致窗口内少了一个字符,right直接移动到left之前指向的那个字符。
自己的思路存在的问题: 注意题目中t的字符是可重复的,如果不重复的话才可以这样做!
官方思路:
双指针。
难点:
1:如何判断right移动后的的窗口是否包含了t中所有的字符?
可以设置两个hash表(窗口内t中的字符搞一个, t搞一个),对这两个hash表逐个比较,如果存在一个字符,s_hash(该字符)<
t_hash(该字符) 则不满足
2:left right两个指针如何让移动?
right移动一直移动直到移动到可以满足的位置(窗口内元素个数>=t中的元素个数)之后。然后left一个一个进行移动,移动一次判断一次,并对ans更新。
class Solution {
public:
unordered_map<char, int> s_hash, t_hash;
bool enough();
string minWindow(string s, string t) {
//滑动窗口经典题目.
//s_hash记录t中出现的字符的个数,t_hash记录t中字符的个数
int n = s.size(), m = t.size();
for (int i = 0; i < m; ++i) {
t_hash[t[i]]++;
}
int left = 0, right = -1, ans_left, minlen = INT_MAX;
while (right < n - 1) {
right++;
if (t_hash.find(s[right]) != t_hash.end()) {
s_hash[s[right]]++;
}
if (enough()) {
while (left < right && enough()) {
if (right - left + 1 < minlen) {
minlen = right - left + 1;
ans_left = left;
}
if (t_hash.find(s[left]) != t_hash.end()) {
s_hash[s[left]]--;
}
left++;
}
if (left == right && enough()) {
minlen = right - left + 1;
ans_left = left;
}
}
}
return minlen == INT_MAX ? "" : s.substr(ans_left, minlen);
}
};
bool Solution::enough() {
for (auto &m: t_hash) {
if (s_hash[m.first] < m.second) return false;
}
return true;
}
改进:
上面的代码中,right移动的位置是0-n-1,可以缩小范围,把下标缩减([index1, index2],index1和index2指向的元素都是t中出现的元素)。
//改进如下:
class Solution {
public:
unordered_map<char, int> s_hash, t_hash;
bool enough();
string minWindow(string s, string t) {
int n = s.size(), m = t.size();
int index1 = 0, index2 = n - 1; //下标范围
for (int i = 0; i < m; ++i) {
t_hash[t[i]]++;
}
while (index1 < n && t_hash.find(s[index1]) == t_hash.end()) index1++; //index1移动
while (index2 >= 0 && t_hash.find(s[index2]) == t_hash.end()) index2--; //index2移动
int left = index1, right = index1 - 1, ans_left, minlen = INT_MAX;
while (right < index2) { //right最多移动到index2的位置
right++;
if (t_hash.find(s[right]) != t_hash.end()) {
s_hash[s[right]]++;
}
if (enough()) {
while (left < right && enough()) {
if (right - left + 1 < minlen) {
minlen = right - left + 1;
ans_left = left;
}
if (t_hash.find(s[left]) != t_hash.end()) {
s_hash[s[left]]--;
}
left++;
}
if (left == right && enough()) {
minlen = right - left + 1;
ans_left = left;
}
}
}
return minlen == INT_MAX ? "" : s.substr(ans_left, minlen);
}
};
bool Solution::enough() {
for (auto &m: t_hash) {
if (s_hash[m.first] < m.second) return false;
}
return true;
}
标签:子串,right,hash,minlen,++,最小,enough,leetcode76,left 来源: https://blog.csdn.net/zhangjiaji111/article/details/120841564