滑动窗口算法(二)

一、力扣904——水果成篮

题目解析:

这道题说的是我们有两个篮子,一个篮子只能装一种水果,再给出的示例中,

fruits = [1,2,3,2,2]

数字1是一种水果,数字2是一种水果,数字3是一种水果,我们只能取两种水果,怎么取最多,并输出一共可以摘多少水果数量。

我这里我们用滑动窗口算法解决,定义两个指针left和right从左往右滑动,right负责进窗口,left负责出窗口,那什么时候出窗口呢?

我们知道只有两个篮子,说明只能装两种类型的水果,就如这个例子

fruits = [0,1,2,2]
class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        unordered_map<int,int> hash;
        int left = 0,right = 0;
        int ret = 0;
        int size = fruits.size();
        while(right < size)
        {
            hash[fruits[right]]++; //进窗口
            while(hash.size() > 2)
            {
                //出窗口
                hash[fruits[left]]--;
                if(hash[fruits[left]] == 0)
                {
                    hash.erase(fruits[left]);
                }
                left++;
            }
            ret = std::max(ret,right - left + 1);
            right++;
        }
        return ret;
    }
};

上面说了right负责进窗口,right把所指向的这个值存放到hash表中,当right指向2的时候,两个篮子分别装的是0和1,所以此时不能再装了,也就是hash.size() >2是出窗口条件,这个时候left就要右移了

但如果是这种情况,left右移两个篮子依然装着两种水果,所以我们这里用的是while判断条件

根据这个逻辑从左往右依次遍历,找出两种水果最长的。

代码如下:

class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        unordered_map<int,int> hash;
        int left = 0,right = 0;
        int ret = 0;
        int size = fruits.size();
        while(right < size)
        {
            hash[fruits[right]]++; //进窗口
            while(hash.size() > 2)
            {
                //出窗口
                hash[fruits[left]]--;
                if(hash[fruits[left]] == 0)
                {
                    hash.erase(fruits[left]);
                }
                left++;
            }
            ret = std::max(ret,right - left + 1);
            right++;
        }
        return ret;
    }
};

二、力扣438——找到字符串中所有字母异位词 

题目解析

看到这道题可能会想,什么是异位词,举个例子abc,那它的异位词是

就是a、b、c排列组合,题目中就是让我们找到abc的异位词,并返回起始的索引

这道题我们先用数组记录下p中所有字符,

再定义一个有效字符count,我们依然使用滑动窗口,在s字符串中定义left和right,right一直往右遍历,并把每一个字符放入s所对应的hash数组中, 

当hash2[in - 'a'] <= hash1[in - 'a'],就代表者滑动窗口内存在一个有效字符

我们拿这个举例,left和right都先指向c

进入判断的时候,c是hash1中的有效字符,所以count++

那什么时候出窗口呢?

当滑动窗口这个窗口的大小大于abc.size()的时候,left就要右移了

此时我们要判断left右移的时候,滑出窗口的那个字符是不是有效字符 

最后判定条件是count == p.size()

代码如下:

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        int hash1[26] = {0};
        vector<int> v1;
        for(auto ch:p)
        {
            hash1[ch - 'a']++;
        }
        int hash2[26] = {0};
        int m = p.size();
        for(int left = 0,right = 0,count = 0;right < s.size();right++)
        {
            //进窗口
            char in = s[right];
            hash2[in - 'a']++;
            if(hash2[in - 'a'] <= hash1[in - 'a']) count++;
            //出窗口
            if(right - left + 1 > m)
            {
                char out = s[left];
                if(hash2[out - 'a'] <= hash1[out - 'a']) count--;
                hash2[out - 'a']--;
                left++;
            }
            if(count == m) v1.push_back(left);
        }
        return v1;
    }
};

三、力扣30——串联所有单词的字串

题目解析,这道题其实跟上一道题找到字符串中所有字母异位词是一样的,我们可以把words数组里的每一个字符串当作整体,进行排列组合,再把s中的整体字符串拆分为words子字符串的大小。例如words子字符串大小是3,我们将s字符串可以拆分成bar、foo、foo、bar、the、foo、bar、man。

整体思路其实是跟上一题一样的

但这题还是有部分细节是不同的,当我们写完目前思路代码再继续给大家看

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        unordered_map<string,int> hash1;
        vector<int> v1;
        for(auto e:words)
        {
            hash1[e]++;
        }
        int m = words.size();
        int len = words[0].size();
        unordered_map<string,int> hash2;
        for(int left = 0,right = 0,count = 0;right < s.size();right += len)
        {
            //进窗口
            string in = s.substr(right,len);
            hash2[in]++;
            if(hash2[in] <= hash1[in]) count++;
            //出窗口
            if(right - left + 1 > m*len)
            {
                string out = s.substr(left,len);
                if(hash2[out] <= hash1[out]) count--;
                hash2[out]--;
                left += len;
            }
            if(count == m)
            {
                v1.push_back(left);
            }
        }
       
        return v1;
    }
};

这一份代码目前的测试用例都能够,当我们提交一下会发生这样的报错 

 

我们将s字符串以4个单位一一划分就知道了,所以我们还要加一个循环

 

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        unordered_map<string,int> hash1;
        vector<int> v1;
        for(auto e:words)
        {
            hash1[e]++;
        }
        int m = words.size();
        int len = words[0].size();
       
        for(int i = 0;i < len;i++)
        {
             unordered_map<string,int> hash2;
            for(int left = i,right = i,count = 0;right < s.size();right += len)
        {
            //进窗口
            string in = s.substr(right,len);
            hash2[in]++;
            if(hash2[in] <= hash1[in]) count++;
            //出窗口
            if(right - left + 1 > m*len)
            {
                string out = s.substr(left,len);
                if(hash2[out] <= hash1[out]) count--;
                hash2[out]--;
                left += len;
            }
            if(count == m)
            {
                v1.push_back(left);
            }
        }
        }
        
       
        return v1;
    }
};

四、力扣76——最小覆盖字串

这道题是让我们在s字符串中找到包含t的最小子字符串

这道题我在之前的博客讲了一遍,具体思路也不细讲了 

 

class Solution {
public:
    string minWindow(string s, string t) {
        int hash1[128] = {0};
        int hash2[128] = {0};
        int kind = 0;
        for(auto ch:t)
        {
            if(hash1[ch] == 0)
            {
                kind++;
            }
            hash1[ch]++;
        }
        int minlen = INT_MAX,begin = -1;
        for(int left = 0,right = 0,count = 0;right < s.size();right++)
        {
            //进窗口
            char in = s[right];
            hash2[in]++;
            if(hash2[in] == hash1[in]) count++;
            while(count == kind)
            {
                if(right - left + 1 < minlen)
                {
                    minlen = right - left + 1;
                    begin = left;
                }
                //出窗口
                char out = s[left];
                if(hash2[out] == hash1[out]) count--;
                hash2[out]--;
                left++;
            }
        }
        if(begin == -1)
        {
            return "";
        }
        else
        {
            return s.substr(begin,minlen);
        }
    }
};

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值