题目:Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).

For example,
S = "ADOBECODEBANC"
T = "ABC"

Minimum window is "BANC".

Note:
If there is no such window in S that covers all characters in T, return the emtpy string "".

If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.

前面两个系列讲了O(N*M)和O(NlogM)的解法。下面讲一下O(N)的。人生可不就是一场不停的战斗么。。。?

实际上leetcode已经有这个的详细解法和介绍了,大家可以看看这里

以下部分我翻译自leetcode上的解说。

注意到前面的解法(O(NlogM))用到了一个hash table,一个队列(二娃:C++解法中使用队列来实现charAppearanceRecorder),一个sorted map,真是要有多复杂有多复杂。在面试中,问题通常来说比较短,代码也大多会不超过50行,所以一定要和面试官交流,让他知道你的想法。如果你的思路比较复杂,面试官可能会给出一些提示。如果你半天都找不到好的方法又闷声不响地在那抠,那就悲剧鸟。

我们下面使用 S = "acbbaca" and T = "aba" 来演示这个算法。基本思路是在遍历S的过程中,使用两个指针(合法window的begin和end索引)和两个table(needToFindhasFound),needToFind保存T中每个字母的个数(二娃:相当于我们的needToFill),hasFound保存当前收集到的每个字母的个数。我们也同时使用一个count变量,用来保存当前收集到的字母总数,但是那些收集过了的字母数并不算在count里面。这样的话,当count等于T.length,那我们就知道遇到一个合法的window了。

我们利用end指针来遍历S,假设当前end指向S中的字母x,如果x是T中的字母,hasFound[x]加一。如果hasFound[x]目前还小于等于needToFind[x](二娃:说明字母x还没有收集全或者刚刚收集全哦),那么我们同时也增加count。当合法window的条件满足,也就是count等于T.length,我们立即递增begin指针,并且保证在递增的过程中始终有count等于T.length。

在递增begin指针的过程中,我们怎么样才能保证“始终有count等于T.length”呢?

假设begin指向字母x,如果hasFound[x]大于了needToFind[x],hasFound[x]减去一,同时递增begin。(二娃:这里很有画面感哦。因为当前遇到的x是冗余的靠左的字母,这里的操作其实等价于前面两个算法中的“删除charAppearanceRecorder中相应的字母的链表头节点”,有点儿像一个是lazy去重,一个是eager去重)否则的话,当前的begin就是window的起始索引了。

接下来我们就可以通过end - begin + 1得到当前window的长度了。这里便可以更新最小window长度。

算法实际上首先找到第一个合法的window,然后在接下来的扫描过程中保持window的合法性(二娃:其实就是count 始终小于等于(当遇到新window)T.length)。

看下面的图图。

i)S = "acbbaca" and T = "aba".

ii)找到第一个合法的window。这里注意我们不能递增begin指针因为hasFound['a'] 等于 needToFind['a'],即2. 如果我们此时递增begin,那就不是合法window了。

iii)找到第二个合法的window。begin指针指向第一个a,hasFound['a']等于3,而needToFind['a']等于2,说明这个a是一个冗余的a,我们递减hasFound['a']同时递增begin。

iv)我们也需要跳过那些不在T中的字母,例如上面的c。现在beging指向了b,hasFound['b']等于2,大于了needToFind['b'],说明这也是一个冗余的b,我们递减hasFound['a']同时递增begin。

v)begin指向b,这时候hasFound['b']等于needToFind['b']。不能再减了,同时begin也不能再次移动了,这里就是一个短window的起点位置。

begin和end都最多前进N次,从而整个算法执行小于2N. 复杂度是O(N)。

上述算法的代码如下:

 public String minWindow3(String S, String T){
HashMap<Character, Integer> needToFill = new HashMap<Character, Integer>();
HashMap<Character, Integer> hasFound = new HashMap<Character, Integer>();
int count = 0;
for(int i = 0; i < T.length(); i++){
if(!needToFill.containsKey(T.charAt(i))){
needToFill.put(T.charAt(i), 1);
hasFound.put(T.charAt(i), 0);
}else {
needToFill.put(T.charAt(i), needToFill.get(T.charAt(i)) + 1);
}
}
int minWinBegin = -1;
int minWinEnd = S.length();
for(int begin = 0, end = 0; end < S.length(); end++){
char c = S.charAt(end);
if(needToFill.containsKey(c)){
hasFound.put(c, hasFound.get(c) + 1);
if(hasFound.get(c) <= needToFill.get(c)){
count++;
}
if(count == T.length()){
while(!needToFill.containsKey(S.charAt(begin)) ||
hasFound.get(S.charAt(begin)) > needToFill.get(S.charAt(begin))) {
if(needToFill.containsKey(S.charAt(begin))
&& hasFound.get(S.charAt(begin)) > needToFill.get(S.charAt(begin))){
hasFound.put(S.charAt(begin), hasFound.get(S.charAt(begin)) - 1);
}
begin++;
}
if(end - begin < minWinEnd - minWinBegin){
minWinEnd = end;
minWinBegin = begin;
}
}
}
}
return minWinBegin == -1 ? "" : S.substring(minWinBegin, minWinEnd + 1);

O(n)

这个算法的亮点是只用一个整型变量就判断了是否是一个合法window。

该算法教育我们:

1.做题要有画面感,而且是精确的画面感;

2.如果用了超过2个复杂数据结构,应该考虑是否有更简单的思路。;

3.人生是一场不停的战斗,不断优化你的算法。

LeetCode 笔记系列16.3 Minimum Window Substring [从O(N*M), O(NlogM)到O(N),人生就是一场不停的战斗]的更多相关文章

  1. LeetCode 笔记系列16.2 Minimum Window Substring [从O(N*M), O(NlogM)到O(N),人生就是一场不停的战斗]

    题目:Given a string S and a string T, find the minimum window in S which will contain all the characte ...

  2. LeetCode 笔记系列16.1 Minimum Window Substring [从O(N*M), O(NlogM)到O(N),人生就是一场不停的战斗]

    题目: Given a string S and a string T, find the minimum window in S which will contain all the charact ...

  3. LeetCode 76. 最小覆盖子串(Minimum Window Substring)

    题目描述 给定一个字符串 S 和一个字符串 T,请在 S 中找出包含 T 所有字母的最小子串. 示例: 输入: S = "ADOBECODEBANC", T = "ABC ...

  4. Minimum Window Substring @LeetCode

    不好做的一道题,发现String Algorithm可以出很多很难的题,特别是多指针,DP,数学推导的题.参考了许多资料: http://leetcode.com/2010/11/finding-mi ...

  5. LeetCode解题报告—— Minimum Window Substring && Largest Rectangle in Histogram

    1. Minimum Window Substring Given a string S and a string T, find the minimum window in S which will ...

  6. 【LeetCode】76. Minimum Window Substring

    Minimum Window Substring Given a string S and a string T, find the minimum window in S which will co ...

  7. 53. Minimum Window Substring

    Minimum Window Substring Given a string S and a string T, find the minimum window in S which will co ...

  8. leetcode76. Minimum Window Substring

    leetcode76. Minimum Window Substring 题意: 给定字符串S和字符串T,找到S中的最小窗口,其中将包含复杂度O(n)中T中的所有字符. 例如, S ="AD ...

  9. 刷题76. Minimum Window Substring

    一.题目说明 题目76. Minimum Window Substring,求字符串S中最小连续字符串,包括字符串T中的所有字符,复杂度要求是O(n).难度是Hard! 二.我的解答 先说我的思路: ...

随机推荐

  1. 大数据量下MySQL插入方法的性能比较

    不管是日常业务数据处理中,还是数据库的导入导出,都可能遇到需要处理大量数据的插入.插入的方式和数据库引擎都会对插入速度造成影响,这篇文章旨在从理论和实践上对各种方法进行分析和比较,方便以后应用中插入方 ...

  2. How To run OAI eNB (No S1) with USRP X310(1)

    How To run OAI eNB (No S1) with USRP X310 1.Things need to be done 1.1 Install Ubuntu 14.04 1.1.1 In ...

  3. Web Socket rfc6455 握手 (C++)

    std::string data((const char*)buf->data(),bytes_transferred); recycle_buffer(buf); std::string ke ...

  4. 用EA生成实体层代码

    在个人版机房重构中.实体层的代码敲得有点儿烦了.不同的实体仅仅是命名不同.代码结构全然一样.遇到反复的事情,就该动动脑.想想办法了. 以下给大家介绍使用EA生成实体层的代码. 首先.建一个类,注意选择 ...

  5. cocos2d-x onMouseMove中CCTouch *pTouch参数的细节

    /**************************************************************************** Copyright (c) 2010 coc ...

  6. Selenium - 设置元素等待

    一.sleep () 休眠方法   --time 固定等待 在开发自动化框架过程中,最忌讳使用Python自带模块的time的sleep方法进行等待,虽然可以自定义等待时间,但当网络条件良好时, 依旧 ...

  7. MUTT+MSMTP利用163服务器发送邮件

    监控系统发送告警邮件,我们自己搭建邮件服务器,成本较高,所以可以使用163等第三方MTA帮助我们发送.MUTT+MSMTP是一个很好的选择,具体实现如下: tar -xvf msmtp-1.6.5.t ...

  8. URL与URI

    1.URI是统一资源标识符,是一个用于标识某一互联网资源名称的字符串. 该种标识允许用户对任何(包括本地和互联网)的资源通过特定的协议进行交互操作.URI由包括确定语法和相关协议的方案所定义.由是三个 ...

  9. dp之多重背包poj2392

    题意:有k种石头,高为hi,在不超过ai的高度下,这种石头可以放置,有ci种这个石头,求这些石头所能放置的最高高度......... 思路:以往的什么硬币种数,最大硬币数之类的,他们的硬币都已经是排好 ...

  10. SpringMVC 之类型转换Converter 源代码分析

    SpringMVC 之类型转换Converter 源代码分析 最近研究SpringMVC的类型转换器,在以往我们需要 SpringMVC 为我们自动进行类型转换的时候都是用的PropertyEdito ...