【滑动窗口】算法实战

这篇具有很好参考价值的文章主要介绍了【滑动窗口】算法实战。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


一、算法原理

滑动窗口,顾名思义,就是有一个大小可变的窗口,左右两端方向一致的向前滑动右端固定,左端滑动;左端固定,右端滑动)。

【滑动窗口】算法实战,基础算法,算法,c++

滑动窗口的本质其实也是一种双指针算法,它是根据单调性的思想,使用”同向双指针“,索引字符串或者列表中的一个区间[left,right]

滑动窗口的步骤一般如下所示:

1、在序列中使用双指针中的左右指针技巧,初始化 left = right = 0,把索引闭区间 [left, right] 称为一个窗口。
2、先不断地增加 right 指针扩大窗口 [left, right],直到窗口中的序列符合要求。
3、此时,停止增加 right,转而不断增加 left 指针缩小窗口 [left, right],直到窗口中的序列不再符合要求。同时,每次增加 left前,都要更新一轮结果。
4、重复第 2 和第 3 步,直到 right 到达序列的尽头。


二、算法实战

1. leetcode209 长度最小的子数组

【滑动窗口】算法实战,基础算法,算法,c++
长度最小的子数组

解题思路:

【滑动窗口】算法实战,基础算法,算法,c++

代码实现:

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int left = 0, right = left, n = nums.size() - 1;
        int Min = 0, sum = 0;
        while(right <= n)
        {
            sum += nums[right];
            while(sum >= target)
            {
                int tmp = right - left + 1;
                Min = Min == 0 ? tmp : min(tmp, Min);
                sum -= nums[left++];
            }
            right++;
        }
        
        return Min;
    }
};

【滑动窗口】算法实战,基础算法,算法,c++


2. leetcode3 无重复字符的最长子串

【滑动窗口】算法实战,基础算法,算法,c++
无重复字符的最长字串

解题思路:滑动窗口+哈希表

题目要求的是无重复字符,为了统计每个字符出现的次数,这里我们可以使用哈希表来统计每个字符出现的次数。

【滑动窗口】算法实战,基础算法,算法,c++

代码实现:

class Solution {
public:
    //滑动窗口问题
    int lengthOfLongestSubstring(string s) {
        int hash[128] = {0};
        int n = s.size() - 1, len = 0;
        for(int left = 0, right = 0; right <= n; right++)
        {
            hash[s[right]]++; // 进窗口
            while(hash[s[right]] > 1)
            {
                hash[s[left]]--;//不满足要求,出窗口,直到满足要求为止
                left++;
            }
            len = max(len, right - left + 1);
        }
        return len;
    }
};

【滑动窗口】算法实战,基础算法,算法,c++


3. leetcode1004 最大连续1的个数

【滑动窗口】算法实战,基础算法,算法,c++
最大连续1的个数III

解题思路:

因为数组中除了0就是1,题目要求我们最多只能翻转k个0,求的是翻转k个0后,最长连续1的个数。

我们可以转换一下思路:找出最长的子数组,该子数组中0的个数不超过k个。

【滑动窗口】算法实战,基础算法,算法,c++

代码实现:

class Solution {
public:
    int longestOnes(vector<int>& nums, int k) {
        int n = nums.size();
        int zero = 0, ret = 0;
        for(int left = 0, right = 0; right < n; right++)
        {
            if(nums[right] == 0)
                zero++;
            while(zero > k)
            {
                if(nums[left] == 0)
                    zero--;
                left++;
            }
            ret = max(ret, right - left + 1);
        }
        return ret;
    }
};

【滑动窗口】算法实战,基础算法,算法,c++


4. leetcode1685 将x减到0的最小操作数

【滑动窗口】算法实战,基础算法,算法,c++
将x减到0的最小操作数

这个题目我们可以进行进一步转化:转换为——> 找出最长的子数组的的长度,所有元素的和正好等于 sum-x,然后再利用滑动窗口解决即可。

代码实现:

class Solution {
public:
    int minOperations(vector<int>& nums, int x) {
        int n = nums.size();
        int sum = 0, target = 0;
        for(int i = 0; i < n; i++)
            sum += nums[i];
        target = sum - x, sum = 0;
        int len = -1;
        
        if(target < 0) return -1;
        for(int left = 0, right = 0; right < n; right++)
        {
            sum += nums[right]; // 进窗口
            while(sum > target) // 判断
            {
                sum -= nums[left++]; // 出窗口
            }
            if(sum == target) // 更新结果
                len = max(len, right - left + 1);
        }
        
        return len == -1 ? len : n - len;
    }
};

【滑动窗口】算法实战,基础算法,算法,c++


5. leetcode904 水果成篮

【滑动窗口】算法实战,基础算法,算法,c++
水果成篮

这道题目的解法是利用滑动窗口+哈希表,数组中的元素表示水果种类的编号,我们只需要利用滑动窗口来进行解决,找到在篮子中的水果种类不超过2的情况下,求出窗口最长的情况即可。

代码实现:

class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        int n = fruits.size(), hash[100010] = {0}, kinds = 0, len = 0;
        for(int left = 0, right = 0; right < n; right++)
        {
            if(++hash[fruits[right]] == 1) // 进窗口
                kinds++;
            while(kinds > 2) // 判断
            {
                if(--hash[fruits[left++]] == 0) // 出窗口
                    kinds--;
            }
            if(kinds <= 2) // 更新结果
                len = max(len, right - left + 1);
        }
        return len;
    }
};

【滑动窗口】算法实战,基础算法,算法,c++


6. leetcode438 找到字符串中所有字母异位词

【滑动窗口】算法实战,基础算法,算法,c++
找到字符串中所有字母异位词

这道题目依旧是利用滑动窗口+哈希表,我们可以先统计目标单词中出现的次数,将其映射到哈希表。维护一个判断窗口中有效字符的个数的变量cnt,从左向右依次利用滑动窗口遍历即可,这里因为单词的长度是固定的,因此每进一个窗口、如过窗口长度大于单词的长度,就必须让最左边的元素出窗口。

代码实现:

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> ret;
        int hash1[26] = {0}, hash2[26] = {0}, len = p.size();
        for(auto&e : p)
            hash2[e - 'a']++;
        int cnt = 0;//判断窗口中的有效字符
        for(int left = 0, right = 0; right < s.size(); right++)
        {
            if(++hash1[s[right] - 'a'] <= hash2[s[right] - 'a']) //进窗口
                cnt++;
            if(right - left + 1 > len) // 判断
            {
                if(--hash1[s[left] - 'a'] < hash2[s[left] - 'a']) //出窗口
                    cnt--;
                left++;
            }
            //判断结构是否合法
            if(cnt == len) // 更新结果
                ret.emplace_back(left);
        }
        return ret;
    }
};

【滑动窗口】算法实战,基础算法,算法,c++


7. leetcode30 串联所有单词的子串

【滑动窗口】算法实战,基础算法,算法,c++
串联所有单词的子串

这道题目和上一道题目很相似,无非就是上一道题目解决的是字符,这道题目解决的是字符串。依然使用的方法是滑动窗口+哈希表,因为这里提前告诉我了我们——目标字符串数组中的每个单词的长度都相同。所以根据这个条件我们可以大大降低时间复杂度。

【滑动窗口】算法实战,基础算法,算法,c++

这里我们需要注意的是,滑动窗口在出入窗口的过程中,移动的步长是单词的长度,滑动窗口执行的次数是单词的长度次。

代码实现:

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        unordered_map<string,int> hash2;//开两个哈希表
        for(auto& e : words)
            hash2[e]++;
        vector<int> ret;
        ret.reserve(s.size());
        int len = words.size(), cnt = 0, n = words[0].size();
        for(int i = 0; i < n; i++) // 执行n次
        {
            unordered_map<string,int> hash1; // 维护窗口内单词的频次
            cnt = 0; 
            for(int left = i, right = i + n; right <= s.size(); right += n)
            {
                string tmp = s.substr(right - n, n);
                if(hash2.count(tmp) && ++hash1[tmp] <= hash2[tmp])
                    cnt++;
                if(right - left > n*len) // 出窗口,维护cnt
                {
                    string tmp = s.substr(left, n);
                    if(hash2.count(tmp) && --hash1[tmp] < hash2[tmp])
                        cnt--;
                    left += n;
                }
                if(cnt == len) // 更新结果
                    ret.emplace_back(left);
            }
        }
        return ret;
    }
};

【滑动窗口】算法实战,基础算法,算法,c++


8. leetcode76 最小覆盖子串

【滑动窗口】算法实战,基础算法,算法,c++
最小覆盖子串

这里给出我们的目标字符串t中的字符种类可能是重复出现的。和上面的题目”找到字符串中所有字母异位词“有所不同:这里我们进窗口时的判断条件应该是:当窗口中出现的字符个数等于目标串某个字符的个数时,变量cnt++,这样保证最后入窗口的字符个数等于目标字符串中指定字符个数时,也就是更新条件成立时,窗口中字符的种类 == 目标字符串窗口中的字符个数一定是 >= 目标字符串的字符的。保证了窗口中的字符串一定是能够完全覆盖目标字符串。最后在满足判断更新条件的循环中不断出窗口,直到出到不能在出为止。

代码实现:

class Solution {
public:
    string minWindow(string s, string t) {
        int hash1[128] = {0}, hash2[128] = {0}, kinds = 0;
        for(auto ch : t)
            if(hash2[ch]++ == 0) kinds++;
        int cnt = 0, Min = INT_MAX, begin = -1;
        for(int left = 0, right = 0; right < s.size(); right++)
        {
            if(++hash1[s[right]] == hash2[s[right]])
                cnt++;
            while(cnt == kinds)
            {
                if(right - left + 1 < Min)
                    Min = right - left + 1, begin = left;
                char out = s[left++];
                if(hash1[out]-- == hash2[out])
                    cnt--;
            }
        }
        if(begin == -1) return "";
        else return s.substr(begin, Min);
    }
};

【滑动窗口】算法实战,基础算法,算法,c++


三、总结

滑动窗口算法是在给定特定窗口大小的数组或字符串上执行要求的操作。 该技术可以将一部分问题中的嵌套循环转变为一个单循环,因此它可以减少时间复杂度。 简而言之,滑动窗口算法在一个特定大小的字符串或数组上进行操作,而不在整个字符串和数组上操作,这样就降低了问题的复杂度,从而也达到降低了循环的嵌套深度。文章来源地址https://www.toymoban.com/news/detail-618081.html


到了这里,关于【滑动窗口】算法实战的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 算法——滑动窗口

    滑动窗口大致分为两类:一类是窗口长度固定的,即left和right可以一起移动;另一种是窗口的长度变化(例如前五道题),即right疯狂移动,left没怎么动,这类题需要观察单调性(即指针)等各方面因素综合思考 长度最小的子数组 子数组需要为连续的区间 需要在满足条件的前

    2024年04月10日
    浏览(37)
  • 算法专题整理:滑动窗口

    视频课程:同向双指针 滑动窗口【基础算法精讲 01】_哔哩哔哩_bilibili 滑动窗口也可以理解为双指针法的一种。 滑动窗口的核心在于 连续 !如果需要得到的结果是 满足某种较为明显条件 的 连续 的 子数组 ,可以考虑使用滑动窗口来做。 通常情况下,滑动窗口是 枚举右端

    2024年02月12日
    浏览(48)
  • 【算法|数组】滑动窗口

    给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度**。**如果不存在符合条件的子数组,返回 0 。 示例 1: 示例 2: 示例 3: 暴力解法 这种做法可以很容易想到,可是谁

    2024年02月12日
    浏览(40)
  • 【算法优选】 滑动窗口专题——壹

    基本概念 滑动窗口是一种 基于双指针 的一种思想,两个指针指向的元素之间形成一个窗口。 分类:窗口有两类,一种是 固定大小类 的窗口,一类是 大小动态变化 的窗口。 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长

    2024年02月08日
    浏览(41)
  • 【算法小课堂】滑动窗口

    滑动窗口本质是双指针算法的一种演变 本质上就是同向双指针,窗口的范围就是[left,right) 滑动窗口大致可以分为两类 窗口大小不变的 窗口大小变化的 滑动窗口遇到一些验证重复性的问题的时候可以用哈希表来优化 三步走: 窗口的形成初期 进窗口 开始遍历数组,right一直

    2024年02月07日
    浏览(42)
  • 算法专题二:滑动窗口

    长度最小的子数组 思路一: 思路二: 无重复字符的最长子串 思路一: 最大连续1的个数 开头位0 并且k为0算是一个特殊的情况这样的情况有一些考虑就走不出去前面的0而忽略到后面数组自带1,走不到这些1数据导致记录连续1的个数出问题! 将x减小到0的最小操作数 水果成篮

    2024年02月02日
    浏览(51)
  • 算法笔记--滑动窗口

    力扣209.长度最小子数组 https://leetcode.cn/problems/minimum-size-subarray-sum/ 在这道题中要注意的不仅仅是滑动窗口的问题,更重要的问题是在循环控制中,不恰当的语法使用会导致这道题出现很严重的问题,这导致我做这道题做了很多天,真的很崩溃。 先来看一下循环的控制问题,

    2024年02月11日
    浏览(46)
  • 【算法专题】滑动窗口

    题目链接 - Leetcode -209.长度最小的子数组 Leetcode -209.长度最小的子数组 题目:给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组[numsl, numsl + 1, …, numsr - 1, numsr] ,并返回其长度。 如果不存在符合条件的子数组,返

    2024年02月05日
    浏览(46)
  • 「算法」滑动窗口

    算法需要多刷题积累经验,所以我行文重心在于分析解题思路,理论知识部分会相对简略一些 滑动窗口属于双指针,这两个指针是 同向前行 ,它们所夹的区间就称为“窗口” 啥时候用滑动窗口? 题目涉及到“子序列”、“子数组”、“子串”等概念,要你求和它们相关的

    2024年02月20日
    浏览(43)
  • 【优选算法】—— 滑动窗口类问题

    本期,我给大家带来的是关于滑动窗口类算法的介绍,并通过具体的题目帮助大家思考理解。     目录 (一)基本概念 (二)题目讲解 1、难度:medium 1️⃣长度最小的子数组 2️⃣找到字符串中所有字⺟异位词 2、难度:hard 1️⃣最⼩覆盖⼦串 2️⃣串联所有单词的⼦串 总

    2024年02月02日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包