码迷,mamicode.com
首页 > Windows程序 > 详细

Minimum Window Substring

时间:2015-05-12 15:04:04      阅读:163      评论:0      收藏:0      [点我收藏+]

标签:

https://leetcode.com/problems/minimum-window-substring/

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.

解题思路:

这是比较难的一道题目,如果t中没有重复的字符,还算好做,但是有重复难度就增加不少了。

思路是使用之前用过的sliding window的方法,维护两个指针,分别指向这个窗口的开始和结束。Substring with Concatenation of All Words 和 Longest Substring Without Repeating Characters 都使用过这个方法。

因为T中的字符可能是重复的,我们就需要首先维护一个map,记录t中的字符和它们出现的次数。下面在遍历s的时候,可以维护一个同样的map,然后用它去和t的map比较。也可以直接在t的map上,将value--。如果value减到0,就代表该字符已经全部出现了,再出现就要<0。我们这里使用的是后一种。

当map所有的value都<=0的时候,代表该窗口已经涵盖了t中的所有字符。但是有一个问题,这个判断需要花费O(n)的时间,也就是需要对map做遍历。如何改进?下面的解法是维护了一个count的变量,如果value<0了,count就不++。也就是,仅仅记录当前窗口涵盖有效的t的字符数量,超过t中出现次数的字符的就不记录了。

具体遍历的时候,第一次遇见t中的字符,初始start值,当涵盖了所有的t的字符,该位置为end值。每次比较end - start + 1的大小,也就是width,记录最小的width和此时的start、end值。

那么,遇见第一次符合条件的窗口后,如何移动窗口,以遇见下一个?

思路是这样的,立刻将start往右移动一位,即start++。当然这里的count和map中value的值要相应变化。然后start不断右移,如果当前字符不在T中,当然右移。如果当前字符是T中有的,但是是多余的,也右移。直到正好遇见一个在T中,并且出现次数==T中次数的。因为这是剔除start后,窗口能缩小到的最小范围了,否则就要错过一个应该涵盖的字符!同时再次判断并更新minWidth值。

这样start停止,end继续往后遍历。

public class Solution {
    public String minWindow(String s, String t) {
        Map<Character, Integer> map = new HashMap<Character, Integer>();
        
        for(int i = 0; i < t.length(); i++) {
            if(!map.containsKey(t.charAt(i))) {
                map.put(t.charAt(i), 1);
            } else {
                map.put(t.charAt(i), map.get(t.charAt(i)) + 1);
            }
        }
        
        int start = 0, end = 0, minStart = 0, minEnd = 0;
        int count = 0, minWidth = Integer.MAX_VALUE;
        for(int i = 0; i < s.length(); i++) {
            if(map.containsKey(s.charAt(i))) {
                if(count == 0) {
                    start = i;
                }
                if(map.get(s.charAt(i)) > 0) {
                    count++;
                }
                map.put(s.charAt(i), map.get(s.charAt(i)) - 1);
            }
            if(count == t.length()) {
                end = i;
                if(end - start + 1 < minWidth) {
                    minWidth = end - start + 1;
                    minStart = start;
                    minEnd = i;
                }
                do {
                    if(map.containsKey(s.charAt(start))) {
                        map.put(s.charAt(start), map.get(s.charAt(start)) + 1);
                    }
                    if(map.containsKey(s.charAt(start)) && map.get(s.charAt(start)) > 0) {
                        count--;
                    }
                    start++;
                } while(start <= i && (!map.containsKey(s.charAt(start)) || map.get(s.charAt(start)) < 0));
                
                if(count == t.length()) {
                    if(end - start + 1 < minWidth) {
                        minWidth = end - start + 1;
                        minStart = start;
                        minEnd = i;
                    }
                }
            }
        }
        if(minWidth == Integer.MAX_VALUE) {
            return "";
        }
        return s.substring(minStart, minEnd + 1);
    }
}

这种sliding window的题目面试中比较常见,因为可以将算法复杂度降低很多。但是老实讲,如果遇见难题的话,前面没做过,或者不熟悉,是比较难的。需要好好掌握。

Minimum Window Substring

标签:

原文地址:http://www.cnblogs.com/NickyYe/p/4495935.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!