算法:滑动窗口类型题目的总结

前言

最近在复习算法的时候,发现滑动窗口类型的题目好像在写代码的时候有很强的共性,

多尝试了几道题,发现,诶,好像还真行。

于是,赶紧分享出来给大家看看,到底这个模版行不行,大家一起检查检查,看看有没有问题。

下面,我们先来看几道题目。

题目一:无重复字符的最长子串

题目链接:无重复字符的最长子串

思路:

我们用双指针围出来一个滑动窗口,同时利用哈希表记录下窗口中每个字母的个数

保证这个窗口里所有的字母的个数都是1,

一旦超过1了,就要出窗口,

怎么出窗口呢?

当然是left指针右移,当然右移之前,需要将记录的left位置的字母的个数减一。

每次循环,都检测一次窗口长度,一旦窗口长度比记录的最长长度还大,就立即更新,

最后返回记录的最大窗口大小。

代码:

c 复制代码
int lengthOfLongestSubstring(string s) {
        int hash[128] = {0};
        int left = 0,right = 0;
        int len = 0;

        //首先right < s.size()
        while(right < s.size())
        {
            //入窗口 
            hash[s[right]]++;
            //判断是否需要出窗口
            while(left <= right && hash[s[right]] > 1)
            {
                //出窗口
                hash[s[left++]]--;
            }

            //right此处右移
            right++;

            //更新窗口大小
            len = max(len,right - left);
        }

        //返回值
        return len;
    }

哇,看完第一题就套路拉满了。

题目二:最大连续1的个数 III

题目:

题目链接:最大连续1的个数 III

思路:

我们不需要管什么翻转,鬼知道小于k个,最多要翻转多少个,

我们直接转换思路,
我们需要寻找一个长度最长的区间,这个区间里面0的个数最多为k。

依旧滑动窗口,用双指针围出来一个窗口,这个窗口就是我们要寻找的区间,我们保证区间里面0的个数不超过k。

来了一个数字,不管是1还是0,先入窗口再说,

接着判断是否需要出窗口,

如果需要出窗口,就对left进行右移,同时遇到0了,减去区间里面的0的个数,

不管需不需要出窗口,right都需要右移

同时,每次循环的的最后,都要计算窗口大小,并决定是否需要更新,

最后返回最大的窗口大小即可。

代码:

c 复制代码
int longestOnes(vector<int>& nums, int k) {
        int left = 0,right = 0;
        int len = 0;
        int count = 0;

        //老样子,right < nums.size()
        while(right < nums.size())
        {
            //入窗口
            if(nums[right] == 0)count++;
            //判断是否需要出窗口
            while(left <= right && count > k)
            {
                //出窗口
                if(nums[left++] == 0)count--;
            }
            //right++
            right++;
            //更新窗口大小
            len = max(len,right - left);
        }

        //返回最大的窗口大小
        return len;
    }

真的,完全一摸一样的套路啊

题目三:将 x 减到 0 的最小操作数

题目:

题目链接:将 x 减到 0 的最小操作数

思路:

第一反应肯定是搜索,但是搜索在这个题目时间复杂度实在是太夸张了,显然不可能。

接着思考,想了半天,哇,怎么这么难,稍微瞄一眼答案,发现这个题目需要进行一次题意转换。

正着想实在是太麻烦了,不知道究竟需要调整哪一端,

而如果我们逆向思维,直接计算中间的和。

这道题目要求我们计算左边一段区间和右边一段区间的和为x,

那么整个数字的和 - x 不就等于 中间一段区间的和了吗?

要求最小操作次数,那么我们中间这段区间的长度就要尽可能长。

所以题意就转化成了寻找一段最长的区间,使得这段区间的和为 sum - x。

还是滑动窗口,找到一个窗口使得窗口和 == sum - x。

代码:

c 复制代码
int minOperations(vector<int>& nums, int x) {
        //正难则反,
        //两端不好算,我们算中间,
        //两端的和要等与x
        //中间的和就等于 sum - x
        //也就是要求找一段区间,要长度最长,且区间和 == sum - x;
        int sum = 0; 
        for(auto& e :nums)
        {
            sum+=e;
        }

        int ret = sum - x;

        int left = 0,right = 0;
        int tmp = 0;
        int len = -1;
        //老样子,right < nums.size()
        while(right < nums.size())
        {
            //入窗口
            tmp += nums[right];
            //必须要加上left <= right的限制,不然会越界
            //判断是否需要出窗口
            while(tmp > ret && left <= right)
            {
                //出窗口
                tmp -= nums[left++];
            }
            //right++
            right++;

            //更新窗口大小
            if(tmp == ret)
            len = max(len,right - left);
        }

        //返回最后的符合要求的窗口大小
        return len == -1 ? -1 : nums.size() - len;
    }

真有规律吧!!!

模版总结

一旦我们发现一道题目可以用滑动窗口的思路结局,那么这道题就可以按照下面的步骤写,

首先,定义好left,right,并且定义好其他的用于记录的变量,

接着,right < nums.size() 进行循环

再然后,进窗口

再然后写一个while循环来判断是否需要出窗口

在while循环里面写上出窗口的逻辑,一般都是某某--,left++

出了while循环,无论是否需要出窗口,right都要++

每次循环都要更新窗口大小

最后返回合适的窗口大小即可

相关推荐
未若君雅裁6 小时前
斐波那契数列 - 动态规划实现 详解笔记
java·数据结构·笔记·算法·动态规划·代理模式
断剑zou天涯6 小时前
【算法笔记】从暴力递归到动态规划(三)
java·算法·动态规划
RQ_ghylls6 小时前
2.excel每3行计算一个均值,将高于均值的单元格设置背景红色
算法·均值算法·word·excel
断剑zou天涯6 小时前
【算法笔记】从暴力递归到动态规划(一)
java·算法·动态规划
不爱编程爱睡觉6 小时前
代码随想录算法训练营第二十八天 | 动态规划算法基础、 LeetCode509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯
算法·leetcode·动态规划·代码随想录
这张生成的图像能检测吗6 小时前
(论文速读)多任务深度学习框架下基于Lamb波的多损伤数据集构建与量化算法
人工智能·深度学习·算法·数据集·结构健康监测
小曹要微笑9 小时前
STM32H7系列全面解析:嵌入式性能的巅峰之作
c语言·stm32·单片机·嵌入式硬件·算法
寻星探路9 小时前
JavaSE重点总结后篇
java·开发语言·算法
松涛和鸣11 小时前
14、C 语言进阶:函数指针、typedef、二级指针、const 指针
c语言·开发语言·算法·排序算法·学习方法
yagamiraito_13 小时前
757. 设置交集大小至少为2 (leetcode每日一题)
算法·leetcode·go