leetcode 76. 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 empty string “”.

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

本题题意很简单,不多说了。最直接的解决方法就是暴力穷举,但是肯定会超时。所以要想一下其他的方法。

这个我是参考网上的一个双指针的解法。具体的做法是这样的:使用map对target字符串做计数处理,这样便于判断当前窗口是否满足包含target的所有元素(还要辅助一个计数器count),这个设计很棒,很值得学习。

使用一个start和end指针遍历字符串,每当发现,当前的窗口包含target的所有元素,那么就开始移动start指针,以缩减窗口,找到最优解。如何判断当前窗口包含target所有的元素,这个就是依靠count计数器。详情看代码吧。

这道题很棒,很值得学习,特别是使用map来做计数器。

建议和leetcode 632. Smallest Range 典型的移动窗口做法 一起学习

这两一道题的思路是完全一样的,建议放到一起学习,很班的移动窗口做法

代码如下:

import java.util.HashMap;
import java.util.Map;

public class Solution
{

    /*
     * 双指针思想,尾指针不断往后扫,当扫到有一个窗口包含了所有T的字符,然后再收缩头指针start,
     * 直到不能再收缩为止。
     * 最后记录所有可能的情况中窗口最小的
     * 
     * 
     * 最笨的方法肯定要超时,这个肯定要使用到map数据结构
    */
    public String minWindow(String window, String target) 
    {
        if(window==null || window.length()<=0 || target==null
        || target.length()<=0 || window.length()<target.length())
            return "";

        Map<Character, Integer> needFind=new HashMap<>();
        Map<Character, Integer> hasFind=new HashMap<>();

        for(int i=0;i<target.length();i++)
            needFind.put(target.charAt(i), needFind.getOrDefault(target.charAt(i), 0)+1);

        int start=0,end=0,minLen=window.length()+1,count=0;
        String res="";
        for(;end<window.length();end++)
        {
            char one=window.charAt(end);
            //包含元素,然后去处理
            if(needFind.containsKey(one))
            {
                //修改map
                hasFind.put(one, hasFind.getOrDefault(one, 0)+1);
                //只有在满足target的情况下才做count++,
                //这里的count就是来判断window的截取是否包含target的元素
                if(hasFind.get(one) <= needFind.get(one))
                    count++;
                //只有在找齐所有的元素之后才去做收缩窗口的操作
                if(count==target.length())
                {
                    while(start<end)
                    {
                        //只要不是当前所包含的start++
                        //假如包含,只有计数器大于所需器的的才去做start++,否者直接break
                        //因为在做start++就不满足要求了
                        char beg=window.charAt(start);
                        if(hasFind.containsKey(beg))
                        {
                            if(hasFind.get(beg)>needFind.get(beg))
                            {
                                hasFind.put(beg, hasFind.get(beg)-1);
                                start++;
                            }
                            else 
                                break;
                        }else 
                            start++;
                    }
                    //收缩窗口之后的判断
                    if(end-start+1 < minLen)
                    {
                        minLen=end-start+1;
                        res=window.substring(start, end+1);
                    }   
                }
            }
        }
        return res;
    }


}

下面是C++的做法,就是一个使用双指针和移动窗口来做的,很棒的做法

代码如下:

#include <iostream>
#include <vector>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <queue>
#include <stack>
#include <string>
#include <climits>
#include <algorithm>
#include <sstream>
#include <functional>
#include <bitset>
#include <numeric>
#include <cmath>
#include <regex>
#include <iomanip>
#include <cstdlib>
#include <ctime>

using namespace std;

#include <iostream>
#include <vector>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <queue>
#include <stack>
#include <string>
#include <climits>
#include <algorithm>
#include <sstream>
#include <functional>
#include <bitset>
#include <numeric>
#include <cmath>
#include <regex>
#include <iomanip>
#include <cstdlib>
#include <ctime>

using namespace std;


class Solution
{
public:
    string minWindow(string s, string target)
    {
        if (s.size() <= 0 || target.size() <= 0)
            return s;

        map<char, int> needFind,hasFind;
        for (char c : target)
            needFind[c]++;

        string res;
        int count = 0 , minLen = INT_MAX;
        for (int left = 0, right = 0; right < s.length(); right++)
        {
            char c = s[right];
            if (needFind.find(c) != needFind.end())
            {
                hasFind[c]++;
                if (hasFind[c] <= needFind[c])
                    count += 1;

                while (count >= target.size() && left <= right)
                {
                    if (right - left + 1 < minLen)
                    {
                        minLen = right - left + 1;
                        res = s.substr(left, right - left + 1);
                    }

                    char t = s[left];
                    if (hasFind.find(t) != hasFind.end())
                    {
                        hasFind[t] -= 1;
                        if (hasFind[t] < needFind[t])
                            count -= 1;
                    }
                    left++;
                }
            }
        }
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值