【基础算法总结】滑动窗口一

滑动窗口

  • 1.长度最小的字数组
  • 2.无重复字符的最长子串
  • 3.最大连续1的个数 III
  • 4.将 x 减到 0 的最小操作数

在这里插入图片描述

点赞👍👍收藏🌟🌟关注💖💖
你的支持是对我最大的鼓励,我们一起努力吧!😃😃

1.长度最小的字数组

题目链接:209.长度最小的字数组

题目分析:

在这里插入图片描述
注意题目说的是正整数数组,说明数组里面的数是大于等于0的数。因此这道题我们有一种优化的方法。

题目让找连续的子数组和大于或等于target,并且长度最小。有很多种情况,但是我们选择的是最小长度。
在这里插入图片描述

算法原理

不管什么题,首先我们一定会先想到的是暴力求解,因为只有暴力求解出来了,我们就可以在暴力求解的基础上进行优化!

解法一:暴力枚举出所有的子数组的和
两层for循环,O(N^2)
在这里插入图片描述

注意到此时暴力枚举是有优化的。之前是每次都从前往后走一遍,但是现在定义一个left,一个right初始化都指向0下标,sum+=nums[right],++right。
等到符合要求统计一下长度,

注意题目说的是一个正整数数组,都是大于等于0的数,这个sum是呈现出递增的状态的,单调递增!

在暴力求解中,此时right还要++,但是注意题目本来要求的就是最小长度,此时sum在加上往上走了一步的right的num[right],一定是满足sum>=target,但是len变成5了,一定不会是最终结果,因此当条件已经满足sum>=target ,right就不用动了。right后面也就不用再枚举了。

在这里插入图片描述
那现在让left+1,right和left指向同一下标,然后再重复上面过程,那有个问题,这段区间的和能不能直接算出来?

当然可以。现在sum=8,我只需要把让sum减去num[left],不就是现在left和right所在的区间和算出来吗。没有必要让right傻傻的回退然后重新加。因此right不动,更新sum=6.

在这里插入图片描述
因此我们从暴力枚举中发现两个优化:
一个是right后面不用枚举,一个left++,right不用回退,

所以我们可以使用双指针优化。

解法二:利用单调性,使用 “同向双指针” 来优化

当我们在暴力枚举的策略中发现left和right都是从左向右一个方向移动,我们就称为这两个指针叫做同向指针。同向双指针又称为滑动窗口。

什么是滑动窗口?
本质上是 “同向双指针”,left从左到右移动,right不回退,从左到右移动,用left和right一直维护这个区间的和,然后这两个指针从左向右移动的过程非常像一个窗口在这个数组里滑来滑去。

在这里插入图片描述

什么时候用滑动窗口?
利用单调性,用滑动窗口解决问题。
当我们发现在暴力求解时,两个指针都可以做到不回退,都是向同一个方向移动的时候,此时就可以用滑动窗口。

滑动窗口怎么用?

  1. 初始left=0,right=0,充当窗口左端点,右端点。用left,right标记窗口左区间,右区间。
  2. 进窗口(++right)
  3. 判断
    根据判断决定是否出窗口(++left)
  4. 更新结果
    2,3都有可能会更新结果,看题目要求

进窗口,判断,出窗口一直循环,直到right超过区间长度结束,更新结果看题目要求(进窗口,出窗口都有可能),

在这里插入图片描述

滑动窗口正确性
暴力枚举肯定对的,因为已经把所有子数组的情况都找出来了。虽然滑动窗口并没有把没有把所有情况都枚举出来,但是这里利用单调性,规避了很多没有必要的枚举行为。虽然没有把所有情况真正枚举出来,但是已经判断出有些子数组不是最终结果,已经把所有结果都考虑进来了,所以这种策略是跟暴力枚举是一样正确的。

滑动窗口时间复杂度
进窗口是一个循环,判断也是一个循环。两层循环套在一起。你会觉得时间复杂度O(N^2),但是不能看代码算时间复杂度,要看实际情况分析实际复杂度。实际我们只会让right向前移动,left也向前移动,即使时最坏情况,right移动到最后一个元素,lefi也移动到最后一个元素,因为总共操作次数最多n+n次 整体时间复杂度O(N)
在这里插入图片描述

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        // 使用滑动窗口解决问题

        int n=nums.size(),sum=0,len=INT_MAX;
        for(int left=0,right=0;right<n;++right)
        {
            sum+=nums[right];// 进窗口
            while(sum>=target)// 判断
            {
                len=min(len,right-left+1);// 更新结果
                sum-=nums[left++];// 出窗口
            }

        }
        return len==INT_MAX?0:len;


        // // 1.初始窗口
        // int left=0,right=0,len=INT_MAX;
        // int n=nums.size(),sum=0;
        // while(right<n)//2.进窗口
        // {
        //     sum+=nums[right];
        //     while(sum>=target)
        //     {
        //         //4.更新结果
        //         if(right-left < len)
        //             len=right-left;

        //         //3.出窗口
        //         sum-=nums[left];
        //         ++left;
        //     }
        //     ++right;
        // }
        // return len==INT_MAX?0:len+1;

    }
};

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

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

题目分析:
在这里插入图片描述
子串和子数组都是连续的

在这里插入图片描述
算法原理

首先还是暴力枚举,然后根据暴力枚举进行优化。
以下面为例,两层for循环,但是下面找到的结果都是我们站在上帝角度,编译器并不知到什么时候结束。一般对应判断是否有重复元素,我们都可以用哈希表来解决问题。

使用哈希表,判断是否有重复元素,比如让你判断一个数组是否有重复,或者两个数组是否有重复都可以用哈希映射!
在这里插入图片描述
解法一:暴力枚举+哈希表(判断字符是否重复出现)
O(N^2)

根据解法一做优化,定义一个left,right指针。当right走到有重复的元素后,已经找到一个字串,其中left到right区间每个元素都已经进入hash表。
在这里插入图片描述

此时left向前走一步,但是这个区间还是有重复元素,因此left要走到没有重复的区间才行,
在这里插入图片描述

然后这个时候以前做法是right回退然后重新往下走,但是这里left到right区间元素本来就在hash表里,因此就不需要right回退了,而是向right继续向前走。然后重复上面过程,直到right走到结尾。结束!
在这里插入图片描述

这不就是滑动窗口的思想吗。双向指针,left往前走,right不回退一直往前走!

解法二:利用规律,使用 “滑动窗口” 解决问题

  1. left=0,right=0
  2. 进窗口
  3. 判断
    出窗口
  4. 更新结果

进窗口、判断、出窗口,更新结果是一个大循环过程。直到right到结尾循环结束。其中判断、出窗口是一个小循环。不过时间复杂度还是O(N).

注意更新结果可能在进窗口后,判断后,出窗口后,判断后任意一个地方,看题目要求

本题:

进窗口 ->-> 让字符进入哈希表
判断-> 窗口内出现重复元素
出窗口-> 从哈希表中删除该字符

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int hash[128]={0};//使用数组模拟哈希表
        int n=s.size(),ret=0;
        for(int left=0,right=0;right<n;++right)
        {
            hash[s[right]]++; // 进窗口
            while(hash[s[right]] > 1) // 判断
            {  
                hash[s[left++]]--;//出窗口      
            }
            ret=max(ret,right-left+1);//更新结果
        }
        return ret;
    }
};

总结一下:
利用单调性,使用 双指针 解决问题。
一般left和right,一个指向数组最左边,一个指向数组最右边,然后一次可以排除一批,再然后left++,–right,两个指针是对撞的

这里利用单调性或者利用规律,使用 滑动窗口 解决问题
滑动窗口也使用双指针解决问题,不过left一直从前往后走,right不回退从前往后走,两个指针是同向的。因此滑动窗口本质其实是同向双指针

3.最大连续1的个数 III

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

题目分析:

在这里插入图片描述

题目说的翻转实际上是把0变成1的意思,最多翻转K次,说明小于等于K都是可以的。
在这里插入图片描述

拿到题我们开始肯定想的是暴力求解。如果直接暴力求解,遇到0->1了,那下一次在遍历就有问题了。因此我们换一个思路。这道题不是让转化后最大连续1的个数吗。我们转化为:找出最长的子数组,数组里0的个数不超过K个,这个数组里面0一定能够转化成1。

算法原理:

解法一:暴力枚举+zero计数器

伪代码,两层for循环,统计zero的个数,满足zero>k,统计此时数组长度,然后重新进入循环,注意每次zero都清0
在这里插入图片描述
然后我们根据暴力枚举,看看有没有优化的可能。定义两个指针left,right,right走到zero>k的位置,zero=3,大于k。
在这里插入图片描述
按照暴力求解left++,然后right回溯然后重新往后走。但是我们发现没有必要,现在left往前走一步,你会发现,right还是停留在老位置!这个区间不用在管的!直接丢弃。
在这里插入图片描述
因此,让left一直走到zero<=k的位置。然后right也根本不用回溯然后在重新走,而是直接往后走就行了。
在这里插入图片描述
根据上面的发现,当在暴力枚举中,发现left,right是同向移动的,利用这个规律,使用滑动窗口解决问题

解法二:利用规律,使用滑动窗口

  1. left=0,right=0
  2. 进窗口
  3. 判断
    出窗口
  4. 更新结果

进窗口 -> 如果是1,不理会。如果是0,计数器+1
判断 -> zero>k
出窗口 -> 如果是1,不理会。如果是0,计数器-1
更新结果:在判断之后在更新

在这里插入图片描述

class Solution {
public:
    int longestOnes(vector<int>& nums, int k) {

        int n=nums.size(),len=0,zero=0;
        for(int left=0,right=0;right<n;++right)
        {
            // 进窗口
            if(nums[right] == 0)
                ++zero;
            
            while(zero>k)//判断
            {
                if(nums[left++] == 0) //出窗口
                    --zero;
            }

            //更新结果
            len=max(len,right-left+1);
        }
        return len;

    }
};

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

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

题目分析:

在这里插入图片描述

这道题让每次从数组左右两边移除一个数,然后就是一个新的数组,然后再从新的数组再从左右两边移除一个数。但是如果真的硬着头皮开始做,其实是很困难的。
你并不知道每次是从最左边走还是最右边找。有可能这次左边下次右边或者还是左边,情况太复杂了。

在这里插入图片描述

因此我们可以利用正难则反的思想
正对面解题太难,那就想对立面,换个思路。
不是每次从左右两端找一个数吗,那可能找到情况就是a+b=x,a、b什么情况都要,但是中间这个连续区间的和不也是确定的吗sum-x,也就是这道题我们转换成,找出最长的子数组长度,所有元素的和正好等于sum-x,然后数组总长减去这段子区间长度不就是问题答案吗,如果没找到说明这个数组不存在将x减到0的数,直接返回-1
在这里插入图片描述

解法一:暴力求解

初始left,right指向同一下标,当right走到和大于target的时候,left往前走,按照暴力求解,right要回到和left相同下标,然后right在重新往前走,直到再次走到和大于target的地方停下来,然后重复上面过程。
在这里插入图片描述

但是今天这里不需要right回溯,因为right回溯后重新走到下面的位置,因为left已经往前走了,这段区间的和肯定是更小了,因此就不需要right回溯了。要么right不动,要么right往后走。
同向双指针 ----> 本质就是滑动窗口
在这里插入图片描述
解法二:使用滑动窗口

在这里插入图片描述

class Solution {
public:
    int minOperations(vector<int>& nums, int x) {
        int sum = 0;
        for (auto& e : nums)
            sum += e;
        int target = sum - x;

        //细节问题
        //数组里都是正整数,才能使用滑动窗口
        //如果让在一个正整数数组里找和为负数的根本不可能
        if (target < 0)
            return -1;

        sum = 0;
        int len = -1;
        for (int left = 0, right = 0; right < nums.size(); ++right)
        {
            sum += nums[right];//进窗口

            while (sum > target)//判断
            {
                sum -= nums[left++];//出窗口
            }

            if (sum == target)//更新结果
            {
                len = max(len, right - left + 1);
            }
        }

       if(len == -1) return len;
       else return nums.size()-len;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/586574.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

利用大型语言模型提升个性化推荐的异构知识融合方法

在推荐系统中&#xff0c;分析和挖掘用户行为是至关重要的&#xff0c;尤其是在美团外卖这样的平台上&#xff0c;用户行为表现出多样性&#xff0c;包括不同的行为主体&#xff08;如商家和产品&#xff09;、内容&#xff08;如曝光、点击和订单&#xff09;和场景&#xff0…

《QT实用小工具·四十九》QT开发的轮播图

1、概述 源码放在文章末尾 该项目实现了界面轮播图的效果&#xff0c;包含如下特点&#xff1a; 左右轮播 鼠标悬浮切换&#xff0c;无需点击 自动定时轮播 自动裁剪和缩放不同尺寸图片 任意添加、插入、删除 单击事件&#xff0c;支持索引和自定义文本 界面美观&#xff0c;圆…

服务器部署开源大模型完整教程 Ollama+Llama3+open-webui

前言 最近大语言模型大火&#xff0c;正好最近打比赛可能会用得上LLMs&#xff0c;今天就在学校的服务器上面进行一次部署。这样之后就可以直接在内网里面使用学校的LLMs了。 介绍 Ollama&#xff1a;一款可以让你在本地快速搭建大模型的工具 官网&#xff1a;https://olla…

基于uniapp vue3.0 uView 做一个点单页面(包括加入购物车动画和左右联动)

1、实现效果&#xff1a; 下拉有自定义组件&#xff08;商品卡片、进步器、侧边栏等&#xff09;源码 2、左右联动功能 使用scroll-view来做右边的菜单页&#xff0c;title的id动态绑定充当锚点 <scroll-view :scroll-into-view"toView" scroll-with-animation…

【C++】封装哈希表 unordered_map和unordered_set容器

目录​​​​​​​ 一、unordered系列关联式容器 1、unordered_map 2、unordered_map的接口 3、unordered_set 二、哈希表的改造 三、哈希表的迭代器 1、const 迭代器 2、 operator 3、begin()/end() ​ 4、实现map[]运算符重载 四、封装 unordered_map 和 unordered_se…

基于t972 Android9 AP6256,如何在设置中添加5G热点选项,并使其正常打开

通过设置的的WiFi热点选项可以知道关键词“2.4GHz”&#xff0c;因此可以其全局搜索&#xff0c;在packages\apps\Settings\res\values\strings.xml文件下找到如下图所示&#xff0c; 从上面注释可以知道&#xff0c;选项按键选择2.4GHz触发的按键关键词是“wifi_ap_choose_2G…

JAVA读取从WPS在Excel中嵌入的图片资源

读取从WPS在Excel中嵌入的图片资源 引言 许多数据文件中可能包含嵌入式图片&#xff0c;这些图片对于数据分析和可视化非常重要。然而&#xff0c;从 WPS 在 Excel 中读取这些图片可能会有一些技术挑战。在本文中&#xff0c;我将展示如何从 WPS Excel 文件中读取嵌入的图片&am…

安居水站:心理咨询的一般伦理原则

正文字数&#xff1a; 1157 图片数&#xff1a; 24 阅读时间&#xff1a;大约4分钟 摘要&#xff1a;心理咨询是帮助个体解决心理问题的重要手段。为确保咨询的有效性和咨询对象的权益&#xff0c;心理咨询必须遵循一定的伦理原则。本文详细探讨了心理咨询…

PDF高效编辑器,支持修改PDF文档并转换格式从PDF文件转换成图片文件,轻松管理你的文档世界!

PDF文件已成为我们工作、学习和生活中不可或缺的一部分。然而&#xff0c;传统的PDF阅读器往往只能满足简单的查看需求&#xff0c;对于需要频繁编辑、修改或转换格式的用户来说&#xff0c;就显得力不从心。现在&#xff0c;我们为您带来一款全新的PDF高效编辑器&#xff0c;让…

对话访谈——五问RAG与搜索引擎:探索知识检索的未来

记一次关于RAG和搜索引擎在知识检索方面的对话访谈&#xff0c;针对 RAG 与传统搜索引擎的异同,以及它们在知识检索领域的优劣势进行了深入的探讨。 Q&#xff1a;传统搜索引擎吗&#xff0c;通过召回-排序的两阶段模式&#xff0c;实现搜索逻辑的实现&#xff0c;当前RAG技术也…

Spark Structured Streaming 分流或双写多表 / 多数据源(Multi Sinks / Writes)

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…

使用 scikit-learn 进行机器学习的基本原理-2

介绍 scikit-learn 估计器对象 每个算法都通过“Estimator”对象在 scikit-learn 中公开。 例如&#xff0c;线性回归是&#xff1a;sklearn.linear_model.LinearRegression 估计器参数&#xff1a;估计器的所有参数都可以在实例化时设置&#xff1a; 拟合数据 让我们用 nump…

第7篇:创建Nios II工程之控制LED<二>

Q&#xff1a;上一期我们完成了Quartus硬件工程部分&#xff0c;本期我们创建Nios II软件工程这部分。 A&#xff1a;创建完BSP和Nios II Application之后&#xff0c;在source文件main.c中添加LED控制代码&#xff1a;system.h头文件包含了Platform Designer系统中IP的硬件信…

VUE3----Tabs swiper 滑动切换

Tabs swiper 滑动切换 <template><view class"cc-tab-container"><scroll-view class"tab-head" :class"tabClassName" scroll-x"true" scroll-with-animation :scroll-left"state.scrollLeft"><view…

变电站综合自动化系统:Modbus-PLC-645转IEC104网关方案

前言 电力行业作为关系国计民生的重要基础产业&#xff0c;是关系千家万户的公用事业。但是要做好电力行业安全保障工作的前提&#xff0c;是需要对应的技术人员详细了解电力工业使用的系统、设备以及各类协议的安全特性&#xff0c;本文将主要介绍IEC 104协议的定义和钡铼技术…

STL——stackqueue

stack stack即为栈&#xff0c;先进后出是其特点 栈只有栈顶元素能被外界使用&#xff0c;故不存在遍历行为 栈中常用接口 构造函数 stack<T> stk; //默认构造方式 stack(const stack &stk); //拷贝构造 赋值操作 stack& operator(const stack &stk); …

对汉诺塔递归算法的简单理解

一.历史背景:汉诺塔&#xff08;Tower of Hanoi&#xff09;&#xff0c;又称河内塔&#xff0c;是一个源于印度古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子&#xff0c;在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始…

网络安全是智能汽车下一个要卷的方向?

2024年一季度&#xff0c;中国汽车市场延续了2023年的风格&#xff0c;核心就是「卷」。 2023年&#xff0c;我国汽车市场爆发「最强价格战」&#xff0c;燃油车的市场空间不断被挤压&#xff0c;如今只剩下最后一口气。近日乘联会发布4月1-14日最新数据&#xff0c;新能源&am…

基于昇腾AI | 英码科技EA500I使用AscendCL实现垃圾分类和视频物体分类应用

现如今&#xff0c;人工智能迅猛发展&#xff0c;AI赋能产业发展的速度正在加快&#xff0c;“AI”的需求蜂拥而来&#xff0c;但AI应用快速落地的过程中仍存在很大的挑战&#xff1a;向下需要适配的硬件&#xff0c;向上需要完善的技术支持&#xff0c;两者缺一不可。 基于此&…

如何利用仪表构造InfiniBand流量在数据中心测试中的应用

一、什么是Infiniband&#xff1f; 在当今数据爆炸的时代&#xff0c;数据中心作为信息处理的中心枢纽&#xff0c;面临着前所未有的挑战。传统的通信方式已经难以满足日益增长的数据传输需求&#xff0c;而InfiniBand技术的出现&#xff0c;为数据中心带来了全新的通信解决方…
最新文章