滑动窗口算法

长度最小的子数组(mid)

image.png

题目链接:长度最小的子数组

算法思路

解法1:暴力枚举(超时)
「从前往后」枚举数组中的任意⼀个元素,把它当成起始位置。然后从这个「起始位置开始,然后寻找⼀段最短的区间,使得这段区间的和「⼤于等于」⽬标值。将所有元素作为起始位置所得的结果中,找到「最⼩值」即可。
解法2:滑动窗口
由于此问题分析的对象是「⼀段连续的区间」,因此可以考虑「滑动窗⼝」的思想来解这道题。让滑动窗⼝满⾜:从 i 位置开始,窗⼝内所有元素的和⼩于 target (那么当窗⼝内元素之和第⼀次⼤于等于⽬标值的时候,就是 i 位置开始,满⾜条件的最⼩⻓度)。做法:将右端元素划⼊窗⼝中,统计出此时窗⼝内元素的和:

  • 如果窗⼝内元素之和⼤于等于 target :更新结果,并且将左端元素划出去的同时继续判断是否满⾜条件并更新结果(因为左端元素可能很⼩,划出去之后依旧满⾜条件)
  • 如果窗⼝内元素之和不满⾜条件: right++ ,另下⼀个元素进⼊窗⼝。

image.png
为什么滑动窗口可以解决问题,并且时间复杂度更低呢??

  • 这个窗⼝寻找的是:以当前窗⼝最左侧元素(记为 left1)为基准,符合条件的情况。也就是在这道题中,从 left1开始,满⾜区间和 sum >= target 时的最右侧(记为right1)能到哪⾥。
  • 我们既然已经找到从 left1 开始的最优的区间,那么就可以⼤胆舍去 left1 。但是如 果继续像⽅法⼀⼀样,重新开始统计第⼆个元素( left2 )往后的和,势必会有⼤量重复的计算(因为我们在求第⼀段区间的时候,已经算出很多元素的和了,这些和是可以在算下次区间和的时候⽤上的)。
  • 此时, rigth1 的作⽤就体现出来了,我们只需将 left1 这个值从 sum 中剔除。从 right1 这个元素开始,往后找满⾜ left2 元素的区间(此时 right1 也有可能是满 ⾜的,因为 left1 可能很⼩。 sum 剔除掉 left1 之后,依旧满⾜⼤于等于 target )。这样我们就能省掉⼤量重复的计算。

时间复杂度:虽然代码是两层循环,但是我们的 left 指针和 right 指针都是不回退的,两者最多都往后移动 n 次。因此时间复杂度是 O(N)

代码
class Solution {public int minSubArrayLen(int target, int[] nums) {int n = nums.length, sum = 0, len = Integer.MAX_VALUE;for(int left = 0, right = 0; right < n; right++){sum += nums[right]; // 进窗⼝while(sum >= target) // 判断,并且要循环,因为左边元素可能很小,还符合条件{len = Math.min(len, right - left + 1); // 更新结果sum -= nums[left++]; // 出窗⼝}}return len == Integer.MAX_VALUE ? 0 : len;}
}

无重复字符的最长子串(mid)

image.png

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

算法思路

研究的对象依旧是⼀段连续的区间,因此继续使⽤「滑动窗⼝」思想来优化。 让滑动窗⼝满⾜:窗⼝内所有元素都是不重复的。
做法:右端元素 ch 进⼊窗⼝的时候,哈希表统计这个字符的频次:

  • 如果这个字符出现的频次超过 1 ,说明窗⼝内有重复元素,那么就从左侧开始划出窗口,直到 ch 这个元素的频次变为 1 ,然后再更新结果。
  • 如果没有超过 1 ,说明当前窗⼝没有重复元素,可以直接更新结果

image.png

代码
class Solution {public int lengthOfLongestSubstring(String s) {int[] hash = new int [128]; // 用来去重int result = 0;int len = 0;for(int left = 0, right = 0; right < s.length(); right++) {int tmp = s.charAt(right);len++;// 进窗口hash[tmp]++;while(hash[tmp] > 1) {// 出现重复的字符,出窗口hash[s.charAt(left) ]--;left++;len--;} // 更新结果result = Math.max(result, len);    }return result;}
}

最大连续1的个数Ⅲ(mid)

image.png

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

算法思路

不要去想怎么翻转,不要把问题想的很复杂,这道题的结果⽆⾮就是⼀段连续的 1 中间塞了 k个 0 嘛。
因此,我们可以把问题转化成:求数组中⼀段最⻓的连续区间,要求这段区间内 0 的个数不超过 k 个。
既然是连续区间,可以考虑使⽤「滑动窗⼝」来解决问题。
image.png

代码
class Solution {public int longestOnes(int[] nums, int k) {int result = 0;for(int left = 0, right = 0, zero = 0; right < nums.length; right++) {// 进窗口if(nums[right] == 0) {zero++;}// 判断0的个数是否大于kwhile(zero > k) {if(nums[left] == 0) {zero--;}// 出窗口left++;}// 更新结果result = Math.max(result, right - left + 1);}return result;}
}

将x减到0的最小操作数(mid)

image.png

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

算法思路:

题⽬要求的是数组「左端+右端」两段连续的、和为 x 的最短数组,信息量稍微多⼀些,不易理清思路;我们可以转化成求数组内⼀段连续的、和为 sum(nums) - x 的最⻓数组。此时,就是熟悉的滑动窗口问题了。
image.png

代码
class Solution {public int minOperations(int[] nums, int x) {int sum = 0;for(int i = 0; i < nums.length; i++) {sum += nums[i];}sum -= x;// 细节处理if(sum < 0) {return - 1;}int result = -1;for(int left = 0, right = 0; right < nums.length; right++) {// 进窗口sum -= nums[right];// 判断while(sum < 0) {sum += nums[left];left++; // 出窗口}// 更新if(sum == 0) {result = Math.max(result, right - left + 1);}}return result == -1 ? -1 : nums.length - result;}
}

水果成篮(mid)

image.png

题目链接:水果成篮

算法思路:

研究的对象是⼀段连续的区间,可以使⽤「滑动窗⼝」思想来解决问题。
让滑动窗⼝满⾜:窗⼝内⽔果的种类只有两种。
做法:右端⽔果进⼊窗⼝的时候,⽤哈希表统计这个⽔果的频次。这个⽔果进来后,判断哈希表的大小:

  • 如果大小超过 2:说明窗⼝内⽔果种类超过了两种。那么就从左侧开始依次将⽔果划出窗⼝,直到哈希表的大小小于等于 2,然后更新结果;
  • 如果没有超过 2,说明当前窗⼝内⽔果的种类不超过两种,直接更新结果 retsult。

image.png

代码:
class Solution {public int totalFruit(int[] fruits) {Map<Integer,Integer> hash = new HashMap<>(2);int result = 0;for(int left = 0, right = 0; right < fruits.length; right++) {// 进窗口hash.put(fruits[right], hash.getOrDefault(fruits[right], 0) + 1);// 判断while(hash.size() > 2) {// 出窗口hash.put(fruits[left], hash.get(fruits[left]) - 1);if(hash.get(fruits[left]) == 0) {hash.remove(fruits[left]);}left++;}// 更新结果result = Math.max(result, right - left + 1);}return result;}
}

找到字符串中所有的字母异位词(mid)

image.png

题目链接:找到字符串中所有字母异位词

算法思路:
  • 因为字符串 p 的异位词的⻓度⼀定与字符串 p 的⻓度相同,所以我们可以在字符串 s 中构造⼀个⻓度为与字符串 p 的⻓度相同的滑动窗⼝,并在滑动中维护窗⼝中每种字⺟的数量;
  • 当窗⼝中每种字⺟的数量与字符串 p 中每种字⺟的数量相同时,则说明当前窗⼝为字符串 p的异位词;
  • 因此可以⽤两个⼤⼩为 26 的数组来模拟哈希表,⼀个来保存 s 中的⼦串每个字符出现的个数,另⼀个来保存 p 中每⼀个字符出现的个数。这样就能判断两个串是否是异位词。

image.png

代码:
class Solution {public List<Integer> findAnagrams(String s, String p) {char[] ss = s.toCharArray();char[] pp = p.toCharArray();int len = 0;int[] hash1 = new int[26];for(int i = 0; i < pp.length; i++) {hash1[pp[i] - 'a']++;}int[] hash2 = new int[26];List<Integer> result = new ArrayList<>();for(int left = 0, right = 0; right < ss.length; right++) {// 进窗口hash2[ss[right] - 'a']++;len++;// 判断while(len == p.length()) {// 更新结果if(isEqual(hash1, hash2)) {result.add(left);}// 出窗口hash2[ss[left] -  'a']--;left++;len--;}}return result;}private boolean isEqual(int[] hash1, int[] hash2) {for(int i = 0; i < hash1.length; i++) {if(hash1[i] != hash2[i]) {return false;}}return true;}
}

优化:

image.png

class Solution
{public List<Integer> findAnagrams(String ss, String pp) {List<Integer> ret = new ArrayList<Integer>();char[] s = ss.toCharArray();char[] p = pp.toCharArray();int[] hash1 = new int[26]; // 统计字符串 p 中每⼀个字符出现的个数for(char ch : p) hash1[ch - 'a']++;int[] hash2 = new int[26]; // 统计窗⼝中每⼀个字符出现的个数int m = p.length;for(int left = 0, right = 0, count = 0; right < s.length; right++){char in = s[right];// 进窗⼝ + 维护 countif(++hash2[in - 'a'] <= hash1[in - 'a']) count++; if(right - left + 1 > m) // 判断{char out = s[left++];// 出窗⼝ + 维护 countif(hash2[out - 'a']-- <= hash1[out - 'a']) count--; }// 更新结果if(count == m) ret.add(left);}return ret;}
}

串联所有单词的子串(hard)

image.png

题目链接:串联所有单词的子串

算法思路

image.png

代码
class Solution {public List<Integer> findSubstring(String s, String[] words) {List<Integer> result = new ArrayList<>();HashMap<String, Integer> hash1 = new HashMap<>();for(String x : words) {hash1.put(x, hash1.getOrDefault(x, 0) + 1);}int len = words[0].length();int num = words.length;// 执行几次滑动窗口for(int i = 0; i < len; i++) {HashMap<String, Integer> hash2 = new HashMap<>();// 注意边界for(int left = i, right = i, count = 0; right + len <= s.length(); right += len) {// 进窗口String in = s.substring(right, right + len);hash2.put(in , hash2.getOrDefault(in, 0) + 1);// count用来维护有效个数if(hash2.get(in) <= hash1.getOrDefault(in, 0)) count++;// 判断 if(right - left + 1 > len * num) {// 出窗口String out = s.substring(left, left + len);if(hash2.get(out) <= hash1.getOrDefault(out, 0)) count--;hash2.put(out, hash2.get(out) - 1);left += len;}// 更新结果if(count == num) {result.add(left);} }}return result;}
}

最小覆盖子串

image.png

题目链接:最小覆盖子串

算法思路:

image.png

代码:
class Solution {public String minWindow(String s, String t) {StringBuilder sb = new StringBuilder();char[] tt = t.toCharArray();int[] hash1 = new int[128];int kind = 0;// 统计有效字符有多少种for(char x : tt) {if(hash1[x]++ == 0) {kind++;} }char[] ss = s.toCharArray();int[] hash2 = new int[128];int minlen = Integer.MAX_VALUE, begin = -1;for(int left = 0, right = 0, count = 0; right < ss.length; right++) {// 进窗口char in = ss[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 = ss[left++];if(hash2[out]-- == hash1[out]) count--;}}if(begin == -1) return new String();else return s.substring(begin, begin + minlen);}
}

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

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

相关文章

node.js 分布式锁看这篇就够用了

Redis SETNX 命令背后的原理探究 当然&#xff0c;让我们通过一个简单的例子&#xff0c;使用 Redis CLI&#xff08;命令行界面&#xff09;来模拟获取锁和释放锁的过程。 在此示例中 获取锁: # 首先&#xff0c;设置锁密钥的唯一值和过期时间(秒) 127.0.0.1:6379> SET …

工业4.0开放平台通信 统一架构OPC UA的一种测试方法

工业4.0和工业物联网&#xff08;Industrial Internet of Things, IIoT&#xff09;的核心挑战在于设备、机器以及来自不同行业服务之间的安全和标准化的数据和信息交换。 2016年11月工业4.0平台发布了指导纲要《工业4.0产品需要实现哪些准则》&#xff0c;即对于所有位于工业…

数据库:根据学校的业务规则画出E-R图以及数据库模型图,并构建一个简单的数据库

目录 序言 一、需求 二、E-R图 E-R图&#xff1a; 三、关系模式 数据库模型图&#xff1a; 四、在MYSQL中创建数据库 4.1 年级表的创建 4.2 科目表的创建 4.3 学生表的创建 4.4 成绩表的创建 结果如下&#xff1a; 序言 本篇文章我将通过一个具体的例子教会大家大家…

自定义模块加载(Python)

加载自定义模块&#xff0c;系统抛出“找不到文件”异常提示信息。 (笔记模板由python脚本于2024年01月28日 12:50:00创建&#xff0c;本篇笔记适合初通Python的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免…

JavaWeb:商品管理系统(Vue版)

文章目录 1、功能介绍2、技术栈3、环境准备3.1、数据库准备3.2、在新建web项目中导入依赖3.3、编写Mybatis文件3.4、编写pojo类3.5、编写Mybatis工具类3.6、导入前端素材&#xff08;element-ui & vue.js & axios.js&#xff09;3.7、前端页面 4、功能实现4.1、查询所有…

Facebook 广告帐户:多账号运营如何防止封号?

Facebook目前是全球最受欢迎的社交媒体平台之一&#xff0c;拥有超过27亿活跃用户。因此&#xff0c;它已成为个人和企业向全球受众宣传其产品和服务的重要平台。 然而&#xff0c;Facebook 制定了广告商必须遵守的严格政策和准则&#xff0c;以确保其广告的质量和相关性&…

基于STM32的智能手环设计与实现

需要原理图工程&#xff0c;源码&#xff0c;PCB工程的朋友收藏&#xff0c;这篇文章关注我&#xff0c;私我吧&#xff01;&#xff01;&#xff01; 基于STM32的智能手环设计与实现 摘要一、研究背景及意义二、实现功能三、系统方案设计系统方案设计框图3.1 单片机芯片选择3…

PCL 高斯投影正算:大地坐标转高斯投影坐标(C++详细过程版)

目录 一、算法原理二、代码实现三、结果展示四、测试数据PCL 高斯投影正算:大地坐标转高斯投影坐标(C++详细过程版)由CSDN点云侠原创。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、算法原理 二、代码实现 头文件及读取保存函数见:

【Linux】分区向左扩容的方法

文章目录 为什么是向左扩容操作前的备份方法&#xff1a;启动盘试用Ubuntu后进行操作 为什么是向左扩容 Linux向右扩容非常简单&#xff0c;无论是系统自带的disks工具还是apt安装的gparted工具&#xff0c;都有图像化的界面可以操作。但是&#xff0c;都不支持向左扩容。笔者…

Java通过模板替换实现excel的传参填写

以模板为例子 将上面$转义的内容替换即可 package com.gxuwz.zjh.util;import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import java.io.*; import java.util.HashMap; import java.util.Map; import java.io.IOException; impor…

react中优化类名写法(类似与vue的动态class对象方式)

安装和引入方式 npm install classnamesimport classNames form classsnames//render 方法中&#xff0c;需要动态className的地方直接参照上图使用

2024幻兽帕鲁服务器,阿里云配置

阿里云幻兽帕鲁服务器Palworld服务器推荐4核16G配置&#xff0c;可以选择通用型g7实例或通用算力型u1实例&#xff0c;ECS通用型g7实例4核16G配置价格是502.32元一个月&#xff0c;算力型u1实例4核16G是432.0元/月&#xff0c;经济型e实例是共享型云服务器&#xff0c;价格是32…

【Git】windows系统安装git教程和配置

一、何为Git Git(读音为/gɪt/)是一个开源的分布式版本控制系统&#xff0c;可以有效、高速地处理从很小到非常大的项目版本管理。 二、git安装包 有2种版本&#xff0c;Git for Windows Setup和Git for Windows Portable(便携版)两个版本都可以。 三、Git for Windows Por…

宏景eHR FrCodeAddTreeServlet SQL注入漏洞复现

0x01 产品简介 宏景eHR人力资源管理软件是一款人力资源管理与数字化应用相融合,满足动态化、协同化、流程化、战略化需求的软件。 0x02 漏洞概述 宏景eHR FrCodeAddTreeServlet 接口处存在SQL注入漏洞,未经过身份认证的远程攻击者可利用此漏洞执行任意SQL指令,从而窃取数…

AI编译器的前端优化策略

背景 工作领域是AI芯片工具链相关&#xff0c;很多相关知识的概念都是跟着项目成长建立起来&#xff0c;但是比较整个技术体系在脑海中都不太系统&#xff0c;比如项目参与中涉及到了很多AI编译器开发相关内容&#xff0c;东西比较零碎&#xff0c;工作中也没有太多时间去做复盘…

【MySQL】事务

目录 一、事务的概念二、支持事务的存储引擎三、事务的提交方式三、事务的操作四、事务的隔离级别五、一致性 一、事务的概念 事务由一条或多条SQL语句组成&#xff0c;这些语句在逻辑上存在相关性&#xff0c;共同完成一个任务&#xff0c;事务主要用于处理操作量大&#xff…

258:vue+openlayers加载mapbox-style的地图

第258个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+openlayers中添加mapbox地图,跟之前的不同处理方式是,这里采用了ol-mapbox-style插件来加载mapbox地图。具体请参考源代码和API。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现效果 文章目录 示…

STM正点mini-跑马灯

一.库函数版 1.硬件连接 &#xff27;&#xff30;&#xff29;&#xff2f;的输出方式&#xff1a;推挽输出 &#xff29;&#xff2f;口输出为高电平时&#xff0c;P-MOS置高&#xff0c;输出为&#xff11;&#xff0c;LED对应引脚处为高电平&#xff0c;而二极管正&#…

深度学习-循环神经网络-RNN实现股价预测-LSTM自动生成文本

序列模型(Sequence Model) 基于文本内容及其前后信息进行预测 基于目标不同时刻状态进行预测 基于数据历史信息进行预测 序列模型:输入或者输出中包含有序列数据的模型 突出数据的前后序列关系 两大特点: 输入(输出)元素之间是具有顺序关系。不同的顺序,得到的结果应…

java servlet勤工助学家教管系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

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