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

滑动窗口

  • 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.mzph.cn/web/5531.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工作任务管理平台B端实战项目作品集+WebApp项目源文件 figma格式

首先&#xff0c;作品集是什么&#xff1f;通常应该包含什么内容&#xff1f;为什么大家都在做自己的作品集呢&#xff1f; 作品集是个人或公司展示其过往工作成果的集合&#xff0c;通常包括各种专案、作品或成就的范例&#xff0c;用以展示创建者的技能、经验和专业水平。 …

Mysql--创建数据库

一、创建一个数据库 “db_classes” mysql> create database db_classes; mysql> show databases; -------------------- | Database | -------------------- | db_classes | | information_schema | | mysql | | performance_schema | |…

LabVIEW航空发动机主轴承试验器数据采集与监测

LabVIEW航空发动机主轴承试验器数据采集与监测 随着航空技术的迅速发展&#xff0c;对航空发动机性能的测试与监测提出了更高的要求。传统的数据采集与监测方法已难以满足当前高精度和高可靠性的需求&#xff0c;特别是在主轴承试验方面。基于LabVIEW的航空发动机主轴承试验器…

【LocalAI】(10):在autodl上编译embeddings.cpp项目,转换bge-base-zh-v1.5模型成ggml格式,本地运行main成功

1&#xff0c;关于 localai LocalAI 是一个用于本地推理的&#xff0c;与 OpenAI API 规范兼容的 REST API。 它允许您在本地使用消费级硬件运行 LLM&#xff08;不仅如此&#xff09;&#xff0c;支持与 ggml 格式兼容的多个模型系列。支持CPU硬件/GPU硬件。 【LocalAI】&…

2024年武汉东湖高新水测成绩出来了

本次水测通过人员有1016名&#xff0c;通过的人数还是蛮多的&#xff0c;水测其实没有大家想象的那么难&#xff0c;现在职称评审都是水测线下评审的模式进行的。 水平测试分机考&#xff0c;笔试和面试答辩&#xff0c;各区随机安排选其一&#xff0c;机考就相当于考驾照刷题&…

Flutter笔记:Widgets Easier组件库(1)使用各式边框

Flutter笔记 Widgets Easier组件库&#xff08;1&#xff09;&#xff1a;使用边框 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress o…

如何在Linux上安装Python?2024Python安装教程

在Linux上安装Python并不难&#xff0c;对于Ubuntu或Debian系统&#xff0c;使用命令sudo apt install python3&#xff1b;对于CentOS、Red Hat或Fedora系统&#xff0c;使用命令sudo yum install python3。 如何在Linux上安装Python&#xff1f; 确切的安装步骤有所不同&am…

[1671]jsp教材管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 教材管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…

RAGFlow:安装与体验

服务器需要有docker,或者直接访问官方提供的demo: https://demo.ragflow.io/ docker-compose安装 需要确保 vm.max_map_count 不小于 262144 【更多】:sysctl -w vm.max_map_count=262144 克隆仓库:$ git clone https://github.com/infiniflow/ragflow.git 进入 doc…

【介绍下Unity编辑器扩展】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

【17】JAVASE-集合专题【从零开始学JAVA】

Java零基础系列课程-JavaSE基础篇 Lecture&#xff1a;波哥 Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机&#xff0c;Java 仍是企业和开发人员的首选开发平台。…

【Java】java实现文件上传和下载(上传到指定路径/数据库/minio)

目录 上传到指定路径 一、代码层级结构 二、文件上传接口 三、使用postman进行测试&#xff1b; MultipartFile接收前端传递的文件&#xff1a;127.0.0.1:8082/path/uploadFile part接收前端传递的文件&#xff1a;127.0.0.1:8082/path/uploadFileByRequest 接收前端传递…

【webrtc】MessageHandler 2: 基于线程的消息处理:以PeerConnectionClient为例

PeerConnectionClient 前一篇 nullaudiopoller 并么有场景线程,而是就是在当前线程直接执行的, PeerConnectionClient 作为一个独立的客户端,默认的是主线程。 PeerConnectionClient 同时维护客户端的信令状态,并且通过OnMessage实现MessageHandler 消息处理。 目前只处理一…

常见公式的几何解释

本文旨在深入探讨常见数学公式的几何意义&#xff0c;通过直观的图形和解释&#xff0c;帮助读者更好地理解并掌握这些公式的本质。文章首先概述了公式与几何图形之间的紧密联系&#xff0c;然后选取了几个典型的数学公式&#xff0c;进行详细解析。每个公式都将配以相应的几何…

怎么做视频二维码更方便?在线一键生成视频活码二维码

现在经常会发现很多的二维码可以用来展示视频内容&#xff0c;通过这种方式来实现视频的快速分享与传播。二维码是一种成本低传播快的内容传播方式&#xff0c;很多的内容都可以通过生成二维码的方式来分享给其他人&#xff0c;可以同时扫描相同的二维码来获取内容&#xff0c;…

在线听歌播放器 梨花带雨网页音乐播放器 网页音乐在线听 源码

最新梨花带雨网页音乐播放器二开优化修复美化版全开源版本源码下载 下 载 地 址 &#xff1a; runruncode.com/php/19749.html 梨花带雨播放器基于thinkphp6开发的XPlayerHTML5网页播放器前台控制面板,支持多音乐平台音乐解析。二开内容&#xff1a;修复播放器接口问题&am…

《半小时漫画论语》读书笔记

站在几年前看现在的我&#xff0c;感觉多了几分犹豫、内耗&#xff0c;少了几分勇敢。 今天重新读下论语&#xff0c;矫正一下人生态度。 一、论语是什么 论语&#xff0c;主要记载了孔子和他弟子们日常说的话、做的事。 孔子&#xff0c;读书人心中的圣人&#xff0c;中国历…

气象数据nc数据矢量化处理解析及可视化

气象数据可视化是将气象学领域中复杂的数据集转化为图形或图像的过程&#xff0c;以直观展示天气现象、气候模式、趋势和预报结果。气象数据的可视化技术广泛应用于科学研究、气象预报、航空、航海、农业生产、灾害预警系统、城市规划、公众服务等领域。以下是一些关键的气象数…

C++证道之路第十五章友元、异常和其他

友元 友元函数&#xff1a; 友元函数不是类的成员函数&#xff0c;但能够访问类的私有&#xff08;private&#xff09;成员和保护&#xff08;protected&#xff09;成员。友元函数定义在类的外部&#xff0c;但在类的定义中通过friend关键字声明。友元函数可以是普通函数&a…

如何在Spring Boot中配置数据库密码加密

如何在Spring Boot中配置数据库密码加密&#xff1f; alibaba/druid Wiki GitHub 使用ConfigFilter alibaba/druid Wiki GitHub 巧用Druid数据源实现数据库连接密码的加密解密功能 import com.alibaba.druid.filter.config.ConfigTools;public class Testttt {public stat…