LeetCode 76. Minimum Window Substring【滑动窗口模板题】⭐⭐⭐⭐⭐

文章目录

  • 题目描述
  • 知识点
  • 结果
  • 实现
    • 码前思考
    • ~~代码实现~~
    • 代码实现
    • 码后反思
  • 二刷代码

题目描述

LeetCode 76. Minimum Window Substring【滑动窗口模板题】⭐⭐⭐⭐⭐_第1张图片

知识点

滑动窗口

结果

LeetCode 76. Minimum Window Substring【滑动窗口模板题】⭐⭐⭐⭐⭐_第2张图片

实现

码前思考

  1. 这道题目是我学习“滑动窗口”的例题,所以我没有对这道题目进行过独立的思考,是按照别人的思路写的;

代码实现

//滑动窗口问题
//使用双指针进行解题

class Solution {
public:
    string minWindow(string s, string t) {
        //定义双指针,初始化都为最左边
        int left = 0;
        int right = 0;
        
        //定义最小的长度,初始化为无限大
        int len = INT_MAX;
        //存储最小窗口开始的地方,这样start~start+len就是窗口的字符串了
        int start = 0;

        //两个hash,用于存储匹配需求和匹配实际
        unordered_map<char,int> needs;
        unordered_map<char,int> window;

        //初始化needs
        for(int i=0;i<t.size();i++){
            needs[t[i]]++;
        }

        //表示匹配情况,初始为都没有匹配
        int match = 0;

        while(right < s.size()){    //只要还在范围之内
            
            //如果当前字符是needs集合里面的字符
            if(needs.count(s[right])){
                window[s[right]]++;
                //如果满足了匹配条件
                if(window[s[right]] == needs[s[right]]){
                    match++;
                }
            }

            //如果match达到了相应的数量
            while(match == needs.size()){
                //那么接下来就是记录长度并且滑动我们的left指针
                if(right - left + 1 < len ){    //如果长度小于当前最短长度,那么要进行更新
                    len = right - left + 1;
                    start = left;
                }
                //开始进行右移,如果这个字符是needs里面需要的话
                if(needs.count(s[left])){
                    window[s[left]]--;
                    if(window[s[left]] < needs[s[left]]){
                        match--;
                    }
                }
                left++;
            }
            right++;
        }

        string res = ((len == INT_MAX) ? "":s.substr(start,len));

        return res;
    }
};

上面代码写错了!!!!!!!!!!!!!!!!!错在下面:

if(needs.count(s[left])){
    window[s[left]]--;
    if(window[s[left]] < needs[s[left]]){
        match--;
    }
}

代码实现

//滑动窗口问题
//使用双指针进行解题

class Solution {
public:
    string minWindow(string s, string t) {
        //定义双指针,初始化都为最左边
        int left = 0;
        int right = 0;
        
        //定义最小的长度,初始化为无限大
        int len = INT_MAX;
        //存储最小窗口开始的地方,这样start~start+len就是窗口的字符串了
        int start = 0;

        //两个hash,用于存储匹配需求和匹配实际
        unordered_map<char,int> needs;
        unordered_map<char,int> window;

        //初始化needs
        for(int i=0;i<t.size();i++){
            needs[t[i]]++;
        }

        //表示匹配情况,初始为都没有匹配
        int match = 0;

        while(right < s.size()){    //只要还在范围之内
            
            //如果当前字符是needs集合里面的字符
            if(needs.count(s[right])){
                window[s[right]]++;
                //如果满足了匹配条件
                if(window[s[right]] == needs[s[right]]){
                    match++;
                }
            }

            //如果match达到了相应的数量
            while(match == needs.size()){
                //那么接下来就是记录长度并且滑动我们的left指针
                if(right - left + 1 < len ){    //如果长度小于当前最短长度,那么要进行更新
                    len = right - left + 1;
                    start = left;
                }
                //开始进行右移,如果这个字符是needs里面需要的话
                if(needs.count(s[left])){
                    if(window[s[left]] == needs[s[left]]){
                        match--;
                    }
                    window[s[left]]--;
                }
                left++;
            }
            right++;
        }

        string res = ((len == INT_MAX) ? "":s.substr(start,len));

        return res;
    }
};

码后反思

  1. 在这道题目里面,滑动窗口[left,right]表示的是以s[left]为首的字符串,能够满足匹配字符串t中的所有字符的最短字符串是[left,right]。这个定义读起来很抽象,但是如果结合滑动窗口的过程理解就不难了;
  2. 使用滑动窗口,我们始终要明确下面三个方面的知识:
    • right右移是寻找可行解的过程;
    • left右移是寻找最优解的过程;
    • 理解滑动窗口[left,right]表达的含义是什么?

二刷代码

在二刷的时候,我对滑动窗口的理解就是以right为边界能够到达的最短匹配长度了。。。感觉有一点绕,我觉得还是之前的——“滑动窗口[left,right]表示的是以s[left]为首的字符串,能够满足匹配字符串t中的所有字符的最短字符串是[left,right]。” 更好理解一些。

我居然发现了两种理解滑动窗口的思路,真是神奇!

//滑动窗口问题,right移动代表寻找可行解集合,left代表寻找可行解集合中的最小解
class Solution {
public:
    string minWindow(string s, string t) {
        unordered_map<char,int> mps;
        unordered_map<char,int> mpt;
        int lens = s.size();
        int lent = t.size();
        int match=0;
        int curMatch=0;
        int start;
        int end;
        int minSize=INT_MAX;

        for(int i=0;i<lent;i++){
            mpt[t[i]]++;
            match++;//代表匹配的字符
        }

        int left = 0;
        int right = 0;

        while(right<=lens-1){
            char rc = s[right];
            if(mpt.count(rc)!=0){
                if(mps[rc]<mpt[rc]){
                    curMatch++;
                }
                mps[rc]++;
            }

            //如果此时匹配的
            if(curMatch==match){
                //代表匹配,那么需要寻找最短的
                while(true){
                    char lc = s[left];
                    if(mpt.count(lc)==0){
                        left++;
                    }else if(mpt.count(lc)!=0 && mps[lc]>mpt[lc]){
                        left++;
                        mps[lc]--;
                    }else{
                        break;//终止循环
                    }
                }

                if(right-left+1<minSize){
                    start=left;
                    end=right;
                    minSize=right-left+1;
                }
            }

            right++;
        }

        if(minSize==INT_MAX){
            return "";
        }else{
            return s.substr(start,minSize);   
        }
    }
};

你可能感兴趣的:(#,双指针,字符串,双指针,滑动窗口,数据结构,算法)