[leetcode]Minimum Window Substring

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.

解题思路:模拟TCP的滑动窗口协议,用两个哈希表记录窗口中的字符个数,其中一个作为标量记录目标串中字符的出现个数,

另一个作为变量记录当前源串中收集到的目标串上的字符个数,当且仅当第二个收集哈希表的有效字符个数与目标串的长度一致时,

就是一个有效窗口,计算其大小,重要的是要收缩其前端的开始下标,直到记录个数第一次小于目标串长度,然后继续扩展窗口大小

算法最大的时间复杂度O(n) 最多两次扫描

class Solution {
public:
    string minWindow(string s, string t) {
        size_t n = s.size(); //源串长
        size_t m = t.size(); //目标串长
        //用来记录当前源串中所含目标串字符的个数,当且仅当于目标串相等时为一个有效窗口
        int cnt = 0; 
        int start = 0; //起始下标
        int minStart = n; //最小窗口的起始下标
        int minWin = n; //最小窗口大小
        
        int stable[256]; //源串中的字符记数表
        int ttable[256]; //目标串中字符的记数表
        //初始化
        for(size_t j = 0; j < 256; j++){
            stable[j] = 0; ttable[j] = 0;
        }
        //统计t中各个字符的出现次数
        for(size_t j = 0; j < m; j++){
            ttable[t[j]]++;
        }
        //窗口滑动
        size_t i;
        //初始化有效的起始下标
        for(i = 0; i < n; i++){
                if(ttable[s[i]] != 0){
                        start = i;
                        break;
                }
        }
        for(; i < n; i++){
                if(ttable[s[i]] != 0){
                        //统计源串字符在目标串中的个数,目标字符没有达到要求就继续统计
                        if(stable[s[i]] < ttable[s[i]]){ 
                                cnt++;
                        }
                        stable[s[i]]++;
                }
                if(cnt == m){ //有效窗口出现
                        //找出最小边界开始的地方,BBBBBA   BA
                        //收缩窗口
                        while(start < i){
                                if(ttable[s[start]] != 0 && cnt == m){
                                        if(stable[s[start]] == ttable[s[start]]){
                                                break;
                                        }
                                        //一定是stable[s[start]] < ttable[s[start]]的地方
                                        stable[s[start]]--; 
                                }
                                start++;
                        }
                        int tWin = i - start + 1;
                        if(tWin <= minWin){ //计算最小窗口,并保留最小开始小标
                                minStart = start;
                                minWin = tWin;
                        }
                        //收缩窗口
                        while(start < i){
                                if(ttable[s[start]] != 0 && cnt == m){
                                        if(stable[s[start]] == ttable[s[start]]){
                                                cnt--;
                                        }
                                        stable[s[start]]--;
                                }
                                start++;
                                if(ttable[s[start]] != 0 || start >= i) break;
                        }
                }
        }
        if(minStart == n) return "";

        return string(s, minStart, minWin);
    }
};


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值