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.

思路一:O(N*M)

滑动窗口,左右边界分别是 left 和 right (分别指向S中某一在T中也存在的字符)。

(1)判断当前窗口是否包含所有的T中字符,若没有,则更新 right 到下一个字符(在T中也存在的字符);

(2)若当前窗口已经包含了所有的T中字符,比较字符串长度是否最短更新字符串;然后更新 left 到下一个字符(在T中也存在的字符);

首先用数组记录T中每一个字符出现的次数,,即为 hash[256] ,然后记录目前的窗口中T中字符出现的次数,通过比较两数组的区别来判断该窗口是否有效。

即 hasAll 函数。

class Solution {
public:
    string minWindow(string S, string T) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        if(T.length()<=0) return T;
        if(S.length()<=0) return S;
    	vector<int> hash(256,0);
        for(int i=0;i<T.length();i++) hash[T[i]]++;  // hash table
  
        int start = 0;     // the result: start and minlen
        int minlen = S.length()+1;
        int left=-1, right=0;
        vector<int>  count(256,0);
		//get the first char 
		while(right<S.length() && !hash[S[right]]) right++;
		if(right==S.length())  return "";
		count[S[right]] ++;
		left = right;
		int rflag=false; // mask if the right has changed
		while(right<S.length()) {
			while(right<S.length() && !hash[S[right]]) right++;
			if(right==S.length())  break;
			if(rflag) count[S[right]] ++; 
			if(hasAll(T,hash,count)) {
				if(right-left+1<minlen) {
					start = left;
					minlen = right-left+1;
				}
				count[S[left]]--;
				left++;
				while(left<=right && !hash[S[left]]) left++;
				rflag=false;
				if(left>right)  break;
			} else {
				rflag=true;
				right++;
			}
		}
        
		if(minlen==S.length()+1)
			return "";
        return S.substr(start,minlen);    
    }
    
    bool hasAll(string &T, vector<int> &hash,vector<int> &count) {
        for(int i=0;i<T.length();i++){
            if(count[T[i]]<hash[T[i]])
                return false;
        }
        return true;
    }
    
};


上述代码时间复杂度是 O(N*M) ,对大数据无法通过。 

思路二:O(N)

上述代码是可以继续优化的,因为在判断该窗口是否有效时,我们没有必要再遍历一遍T ,即上述代码的子函数:

bool hasAll(string &T, vector<int> &hash,vector<int> &count)

可以在生成窗口的过程中,记录当前已经生成了多少个T中的字符:如果 num=T.length() ,表示该窗口有效,可以更新最优解。

可以通过大数据。

class Solution {  
public:  
    string minWindow(string S, string T) {  

        int sLen = S.length();
        int tLen = T.length();
        // The hashtable used to record the num of letters of T in T and T in S
        int needToFind[256] = {0};
        for (int i = 0; i < tLen; i++)
            needToFind[T[i]]++;
        int hasFound[256] = {0};
        // The window for result: begin and end
        int minWindowLen = INT_MAX;
        int minWindowBegin;
        int minWindowEnd;
        // The num of letters in the window we have
        int count = 0;
        for (int begin = 0, end = 0; end < sLen; end++) {
            // skip characters not in T
            if (needToFind[S[end]] == 0) 
                continue;
            hasFound[S[end]]++;
            if (hasFound[S[end]] <= needToFind[S[end]]) 
                count++;
            // if window constraint is satisfied
            if (count == tLen) {
                // advance begin index as far right as possible,
                // stop when advancing breaks window constraint.
                while (needToFind[S[begin]] == 0 || hasFound[S[begin]]>needToFind[S[begin]]) {
                    if (hasFound[S[begin]] > needToFind[S[begin]])
                        hasFound[S[begin]]--;
                    begin++;
                }
                // update minWindow if a minimum length is met
                int windowLen = end - begin + 1;
                if (windowLen < minWindowLen) {
                    minWindowBegin = begin;
                    minWindowEnd = end;
                    minWindowLen = windowLen;
                } // end if
            } // end if
        } // end for
        if(count<tLen)  
            return "";
        else
            return S.substr(minWindowBegin,minWindowLen);  
    }

};

其实上述代码还可以进一步优化:我们可以记录用一个 Queue 记录每次 right 停止的位置,因为 这些位置也是 left 将要停止的位置。

这样就 没必要进行 上述的 left 循环递增:

                // advance begin index as far right as possible,
                // stop when advancing breaks window constraint.
                while (needToFind[S[begin]] == 0 || hasFound[S[begin]]>needToFind[S[begin]]) {
                    if (hasFound[S[begin]] > needToFind[S[begin]])
                        hasFound[S[begin]]--;
                    begin++;
                }

可以直接弹出 Queue 中的一个 值作为 left 的值看是否满足条件。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值