题目描述
给定两个字符串:$S$ 和 $T$,请找到 $S$ 中最短的一段,包含 $T$ 中所有字符。
注意:
- 如果 $S$ 中不存在这样的方案,则返回
""
; - 如果 $S$ 中存在这样的方案,则数据保证答案一定唯一;
样例
输入:S = "ADOBECODEBANC", T = "ABC"
输出:"BANC"
算法
(滑动窗口) $O(n)$
首先用哈希表统计出 $T$ 中所有字符出现的次数,哈希表可以用C++中的 unordered_map
,不了解用法的同学可以点这里。
然后我们用两个指针 $i, j(i \ge j)$来扫描整个字符串,同时用一个哈希表统计 $i, j$ 之间每种字符出现的次数,每次遍历需要的操作如下:
- 加入 $s[i]$,同时更新哈希表;
- 检查 $s[j]$ 是否多余,如果是,则移除 $s[j]$;
- 检查当前窗口是否已经满足 $T$ 中所有字符,如果是,则更新答案;
时间复杂度分析:两个指针都严格递增,最多移动 $n$ 次,所以总时间复杂度是 $O(n)$。
C++ 代码
class Solution {
public:
string minWindow(string s, string t) {
unordered_map<char, int> hash;
int cnt = 0;
for (auto c : t)
{
if (!hash[c]) cnt ++ ;
hash[c] ++ ;
}
string res = "";
for (int i = 0, j = 0, c = 0; i < s.size(); i ++ )
{
if (hash[s[i]] == 1) c ++ ;
hash[s[i]] -- ;
while (c == cnt && hash[s[j]] < 0) hash[s[j ++ ]] ++ ;
if (c == cnt)
{
if (res.empty() || res.size() > i - j + 1) res = s.substr(j, i - j + 1);
}
}
return res;
}
};
贴一个
注释版
代码,详情剖析版
可以看这里啦 详细题解:膜拜这个cnt 的思路 滑动窗口好写 自己开了两个哈希表来维护条件满足 用了y总思路快了一倍多
加油hh
棒!
哈哈哈哈哈哈 太妙了!!
我夸我自己?
yxchb!
while (c == cnt && hash[s[j]] < 0) hash[s[j ++ ]] ++ ;
这句代码中,
j ++
的意思是删除当前j
指向的这个字符对吗?但是我不理解
hash[s[j]] ++
这里是做什么?窗口中的所有字符,每出现一次,就在哈希表中减一,所以当从窗口中删除一个字符的时候,就加1。
j ++
表示将j
从窗口中删除。python如果没有c==cnt的话左指针可能会越过s字符串边界,需要要判断一下,那为何C++里面就可以通过呢
按道理应该加一下
c == cnt
的判断。不过程序运行过程中如果发生数组越界,是不一定会报错的,运行结果会比较随机。看录播里的代码 是while ( hash[s[j]] < 0) hash[s[j ]] ;这个里面没有c==cnt,但是今天跑了一遍,报错越界了
这里应该加上
c == cnt
,否则j
可能会越界。hash[s[j ++ ]] ++
这样 j 不会越界吗不会滴。
hash[]
中存储的是t
中每个字母出现的次数,减去s[j~i]
中出现的次数,所以当j > i
时,hash[]
中的所有值一定大于等于0,此时循环就会终止。while (c == cnt && hash[s[j]] < 0) hash[s[j ]] ;这一句太厉害了
是的hh 双指针算法的核心啊
请问hash[s[j]] == 0的情况是什么样的?如果s[j]是在t中没有出现的话,那么hash[s[j]]不就是多余的吗?
hash[c]
表示的是当前c
这个字母还缺多少个,hash[s[j]] == 0
表示s[j]
这个字母已经足够了 。如果s[j]
是在t中没有出现的话,hash[s[j]]
可以不用记录,不过记录一下也不影响算法正确性。明白了,也就是说如果一个字母如果没在t中出现的话,会先被–变为-1;那么当hash[s[j]] == 0的时候这个j字母肯定是在t里面出现了的,谢谢y总的解答
嗯嗯不客气
如果加上详细注释就更好啦!