76. Minimum Window Substring

最后更新

一刷
08-Jan-2017

昨天Amazon group面结束,刚回家。
国内以前喜欢的女生结婚了,嘿嘿...好开心呀~~

image

这次面试感觉自己的做法完爆别人,比什么2 greedy好多了= = 总之表现比想象的好,最后一面的面试官真是聪明得一逼,我的思路稍微说她就明白,跪了,这也太出色了。 我只能说A家对于背题党直接OA拿VIDEO或者OFFER确实水,但是有实力的也有,比如给我面试的这个印度姐姐,屌屌屌。

总之希望自己能过能过。

开始准备Google吧。

言归正传。

一长一短2个String

在长的String里找最短的substring,使得substring包含所有短string的字符。
('a'在短字符串里出现2次,substring里也要出现2次才行)

2 pointers来做的,固定左边,右边往右找,直到substring满足要求。 在往右的过程中,我们可能添加了很多不必要元素:
要满足abc
我们在ab baba cba里找,找到C的时候,添加了baba这段没用的,这个时候尝试左边缩进。

比较通过2个int[256],一个是需要的字符数,一个是现有的。

Time: O(n)
Space: O(1)

public class Solution {
    public String minWindow(String s, String t) {
        if (s.length() < t.length()) return "";
        int[] need = new int[256];
        int[] count = new int[256];
        
        for (char c : t.toCharArray()) {
            need[c]++;
        }
        
        int right = 0;
        String res = "";
        int minLength = Integer.MAX_VALUE;
        
        for (int left = 0; left < s.length(); left++) {
            while (right < s.length() && !contains(need, count)) {
                count[s.charAt(right++)] ++;
            }
            
            if (right - left < minLength && contains(need, count)) {

                minLength = right - left;
                res = s.substring(left, right);
            }
            count[s.charAt(left)] --;
        }
        
        return res;
    }
    
    public boolean contains(int[] need, int[] count) {
        for (int i = 0; i < 256; i++) {
            if (need[i] > count[i]) {
                return false;
            }
        }
        return true;
    }
}

方法二:

也是2 pointers,和一的做法差不多,唯一不同的就是判断是否包含的方法。

方法一是通过比较int[256]来判断是否包含所有character,这里有个别的方法。

比如短string是abcde,那么总共需要5个字符才能满足。但也不是随便5个字符就能满足,只有某些字符才能满足。
比如:
一开始是abcde,需要5个才能满足,而a,b,c,d,e其中任何一个都是有效字符。
假如我们substring中已经有了a和c,需要bde,此时的有效字符就变成了b,d,e,读到b,d,e才可以让需要数字++

同理,缩进也要判断,比如substring里有3个A,缩进最左边缩小了1个A,那么当前需要的元素数量是不变的,因为我们还有2个A可以使用,相反如果缩掉了B,而我们substring里没有B了,总共需要的元素数量就要++

if (--chars[s.charAt(right++)] >= 0) {
                    validRead ++;
                }

这个说的是,substring读取一个,然后判断是否是有效读取,把那些-- ++之类的给展开就一目了然了,后面的+ + --一样 ,展开再看。

public class Solution {
    public String minWindow(String s, String t) {
        if (s.length() == 0 || s.length() < t.length()) return "";
        
        String res = "";
        int minLength = Integer.MAX_VALUE;
        
        int[] chars = new int[256];
        for (char c : t.toCharArray()) {
            chars[c] ++;
        }
        int need = t.length();
        int validRead = 0;
        int right = 0;
        for (int left = 0; left < s.length(); left ++) {
            while (right < s.length() && validRead < need) {
                if (--chars[s.charAt(right++)] >= 0) {
                    validRead ++;
                }
            }
            
            if (validRead >= need && right - left < minLength) {
                minLength = right - left;
                res = s.substring(left, right);
            }
            
            if (++chars[s.charAt(left)] > 0) validRead --;   
        }
        
        return res;
    }
}

方法二是因为后面的题要用到这个办法。

原文地址:https://www.cnblogs.com/reboot329/p/6263861.html