【算法】【优选算法】滑动窗口(上)

目录

  • 一、滑动窗口简介
  • 二、209.⻓度最⼩的⼦数组
    • 2.1 滑动窗口
    • 2.2 暴力枚举
  • 三、3.⽆重复字符的最⻓⼦串
    • 3.1 滑动窗口
    • 3.2 暴力枚举
  • 四、1004.最⼤连续1的个数III
    • 4.1 滑动窗口
    • 4.2 暴力枚举
  • 五、1658.将x减到0的最⼩操作数
    • 5.1 滑动窗口
    • 5.2 暴力枚举

一、滑动窗口简介

其实就是利用单调性,使用同向双指针来优化暴力枚举的一种算法。
我们遇到这种题的解法就找如下四个东西:

  • 进窗口;
  • 出窗口条件;
  • 出窗口;
  • 修改结果语句,修改结果语句的位置是不固定的,但上面3个东西的顺序是固定由上到下。

二、209.⻓度最⼩的⼦数组

题目链接:209.⻓度最⼩的⼦数组
题目描述:

题目解析:

  • 这个数组中都是正整数;
  • 在数组中找两个元素和大于等于目标值的最小长度(即下标之差加1)。

2.1 滑动窗口

解题思路:

  • 我们使用sum来记录[left, right]区间中元素的和,
  • 由于题目中说给的元素都为正整数,所以我们left像后走就是将sum减小,而right向后走就是将sum变大。
  • 所以我们进窗口就是求和 sum += nums[right]。
  • 出窗口条件sum >= target,由于出去一个元素,可能sum还是比目标值大,所以这里要使用循环。
  • 出窗口就是sum -= nums[left++]。
  • 修改结果就是求ret 与现在的长度的最小值Math.min(ret, right-left+1)。
  • 这道题的细节问题,由于我们求得长度的最小值,所以初始化结果的时候要使用一个较大的值。

解题代码:

//时间复杂度O(N)
//空间复杂度O(1)
import java.util.*;
class Solution {public int minSubArrayLen(int target, int[] nums) {int ret = 0x3f3f3f3f;int sum = 0;for(int left = 0, right = 0; right < nums.length; right++) {sum += nums[right];//进窗口while(sum >= target) {//判断条件ret = Math.min(ret, right-left+1);//修改结果sum -= nums[left++];//出窗口}            }return ret == 0x3f3f3f3f ? 0 : ret;}
}

2.2 暴力枚举

解题思路:

  • 我们直接使用两层for循环将所有可能枚举出来。
  • 会超时。

解题代码:

//时间复杂度O(N^2)
//空间复杂度O(1)
import java.util.*;
class Solution {public int minSubArrayLen(int target, int[] nums) {int ret = 0x3f3f3f3f;for(int i = 0; i < nums.length; i++) {int sum = nums[i];if(sum >= target) return 1;for(int j = i+1; j < nums.length; j++) {sum += nums[j];if(sum >= target) {ret = Math.min(ret, j-i+1);}}}return ret == 0x3f3f3f3f ? 0 : ret;}
}

三、3.⽆重复字符的最⻓⼦串

题目链接:3.⽆重复字符的最⻓⼦串
题目描述:

题目解析:
-题目要求给得十分清晰,只要我们返回字符串中连续不相同字符构成的子串的长度的最大值即可。

3.1 滑动窗口

解题思路:

  • 当我们已经拿到一个子串,以例1的abcabcbb为例,当我们拿到子串abc的时候下一个是a,我们只需要将子串的起点将重复字符走过就行,所以我们的子串前后都往同一个方向走,使用滑动窗口。
  • 要记录下子串中每个字符的个数,使用hash表的性质,只有一个相同元素,这里的元素是知道的只有ASCII码表中的,直接使用一个数组代替即可,当前子串中元素对应下标的hash[ ]数组的值就是当前子串中含有该元素的个数。
  • 进窗口:就是把每个字符的对应hash数组的元素加一;
  • 出窗口条件:当我们现在进入字符后,hash数组中值大于1;
  • 出窗口:循环出一直出到重复的字符为止。
  • 更新结果:每一次出完了窗口之后的子串就是一个符合条件的子串,只需要求它的长度与原结果的较大值即可。

解题代码:

//时间复杂度O(n)
//空间复杂度O(1)
import java.util.*;
class Solution {public int lengthOfLongestSubstring(String s) {int len = s.length();int left = 0, right = 0, ret = 0;int[] hash = new int[128];while(right < len) {hash[s.charAt(right)]++;//进窗口while( hash[s.charAt(right)] > 1) {//出窗口条件hash[s.charAt(left++)]--;//出窗口}ret = Math.max(ret, right - left + 1);//更新结果right++;}return ret;}
}

3.2 暴力枚举

解题思路:

  • 我们只需要使用两层for循环将每一个连续不相同字符构成的子串枚举出来,然后取最大长度即可。
  • 使用hash表的性质,只有一个相同元素,这里的元素是知道的只有ASCII码表中的,直接使用一个数组代替即可,当前子串中元素对应下标的hash[ ]数组的值就是当前子串中含有该元素的个数。

解题代码:

//时间复杂度O(n^2)
//空间复杂度O(1)
import java.util.*;
class Solution {public int lengthOfLongestSubstring(String s) {int len = s.length();int ret = 0;for(int i = 0; i < len; i++) {int[] hash = new int[128];for(int j = i; j < len; j++) {hash[s.charAt(j)]++;if(hash[s.charAt(j)] > 1) {break;}ret = Math.max(ret, j - i + 1);}}return ret;}
}

四、1004.最⼤连续1的个数III

题目链接:1004.最⼤连续1的个数III
题目描述:

题目解析:

  • 题目给的翻转0,其实意思就是最多有k个0可以变成1,让连续的1的个数最大。

4.1 滑动窗口

解题思路:

  • 这道题求解翻转后子数组中1最多的个数,其实也就是求子数组中<= k个0时的最大长度。
  • 我们只需要使用一个计数器来记录当前子数组中的0的个数。
  • 当我们的计数器没超过k的时候我们需要子数组尾一直向后走,让元素进入子数组,当超过k的时候我们又需要子数组头向后走,出元素让子数组中0的个数小于k,所以这又是一个都向后走的同向双指针问题。
  • 进窗口:right向后走一步进一个元素,并判断是否是0更新计数器。
  • 出窗口条件:计数器中0个数大于k。
  • 出窗口:left++循环直到计数器0个数小于等于k。
  • 更新结果:在出完窗口之后,子数组满足条件,就更新结果,取原结果与新数组长度较大值。

解题代码:

//时间复杂度O(n)
//空间复杂度O(1)
import java.util.*;
class Solution {public int longestOnes(int[] nums, int k) {int len = nums.length;int ret = 0;int numZero = 0;for(int left = 0, right = 0; right < len; right++) {//进窗口if(nums[right] == 0) numZero++;while(numZero > k) {//出窗口条件//出窗口if(nums[left] == 0) numZero--;left++;}ret = Math.max(ret, right - left + 1);}return ret;}
}

4.2 暴力枚举

解题思路:

  • 直接两层for循环将每一个0的个数<= k的子数组列举出来。
  • 细节处理,当我们遇到像这样的序列 [0,0,0,1] k = 4 我们在遍历完数组后都没有超过k,这时我们的长度就是数组长度,可能会有疑惑为啥在最后返回时使用三目运算符 ret == 0 ? nums.length : 0;不就可以了吗,但是如果是[0,0,0,0] k = 0这样的长度本来就该返回0的也会冲突,所以这两种情况我们要处理一种。

解题代码:

//时间复杂度O(n^2)
//空间复杂度O(1)
import java.util.*;
class Solution {public int longestOnes(int[] nums, int k) {int ret = 0;int numZero = 0;for(int i = 0; i < nums.length; i++) {int j = i;numZero = 0;for(; j < nums.length; j++) {if(nums[j] == 0) numZero++;if(numZero > k) {ret = Math.max(ret, j - i);break;}}if(j == nums.length && numZero <= k) return Math.max(ret, j - i);}return  ret;}
}

五、1658.将x减到0的最⼩操作数

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

题目解析:

  • 注意每一步操作都可以删除数组头和数组尾,让删掉的数组元素和刚好等于x,取删掉的数组元素个数最小值。
  • 注意提示的数组元素都是大于0的。
  • 按照题目给的操作,我们每一次的删除都是有两个选择的,这样的不确定性太高,解题非常困难。那么“正难则反”,我们就先求中间的子数组的和,然后用nums的和,减去子数组的和,这个值就是该删除的元素的和了。

5.1 滑动窗口

解题思路:

  • 其实按照上面的思路,又由于数组元素都是正数,要让被删除元素和变大,只需要将中间子数组的向后走即可,
  • 而让被删除元素和变小,只需要将中间子数组的向后走即可。又是同向双指针问题。
  • 进窗口:right向后走一步进一个元素。
  • 出窗口条件:当删掉元素和大于x的时候出窗口。
  • 出窗口:left++循环直到删除元素和小于等于x。
  • 更新结果:在出完窗口之后,判断删除元素和是否等于x,是就更新结果,取原结果与被删除元素个数较小值。
  • 但是有两种情况没考虑:
    • 当我们的整个数组和刚好等于x的时候[4,5] x = 9。
    • 当我们的整个数组和刚都小于x的时候[4,5] x = 8。
  • 这两种情况都有可能导致出窗口条件判断的时候,使数组越界,所以判断条件中还要加上left <= right。

解题代码:

//时间复杂度O(n)
//空间复杂度O(1)
import java.util.*;
class Solution {public int minOperations(int[] nums, int x) {int len = nums.length;int ret = 0x3f3f3f3f;int sum = 0;//求和int sumNums = 0;for(int i = 0; i < len; i++) {sumNums += nums[i];}for( int left = 0, right = 0; right < len; right++) {sum += nums[right];//进窗口while(left <= right && sumNums - sum < x) {//出窗口条件sum -= nums[left++];//出窗口} if(sumNums - sum == x) {ret = Math.min(ret, len - (right - left + 1) );//更新结果}}return ret ==  0x3f3f3f3f ? -1 : ret;}
}

5.2 暴力枚举

解题思路:

  • 直接使用两层for循环来将每一个子数组的可能枚举出来。
  • 当当前的子数组的和与数组nums元素和的差值等于x的时候,就可以更新结果。
  • 还是上面的整个数组和刚好等于x的时候没处理:
    • 等于时直接在前面求和时判断返回即可。
    • 小于在最后使用三目运算符即可。
  • 会超时。

解题代码:

//时间复杂度O(n^2)
//空间复杂度O(1)
import java.util.*;
class Solution {public int minOperations(int[] nums, int x) {int len = nums.length;int ret = 0x3f3f3f3f;//求和int sumNums = 0;for(int i = 0; i < len; i++) {sumNums += nums[i];}if(sumNums == x) return len;for(int i = 0; i < len; i++) {int sum = 0;for(int j = i; j < len; j++) {sum += nums[j];if( (sumNums - sum) == x) {ret = Math.min(ret, len - (j - i + 1));break;}}}return ret == 0x3f3f3f3f ? -1 : ret;}
}

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

软考高级之系统架构师系列之构件开发模型

如标题所述&#xff0c;本文面向于软考高级&#xff0c;具体来说是系统架构师。 有些概念&#xff0c;如生命周期&#xff0c;开发的几个阶段&#xff0c;不同的教程有些许出入。 本文偏理论&#xff0c;要在理解的基础上加以记忆&#xff0c;用于应付软考&#xff0c;有些地…

机器人零位、工作空间、坐标系及其变换,以UR5e机器人为例

机器人中的主要坐标系 在机器人中&#xff0c;常用的坐标系包括&#xff1a; 基坐标系&#xff08;Base Frame&#xff09;&#xff1a;固定在机器人基座上的坐标系&#xff0c;用于描述机器人的整体位置和方向&#xff0c;是其他所有坐标系的参考点。 连杆坐标系&#xff08…

VMWARE ESXI VMFS阵列故障 服务器数据恢复

1&#xff1a;河南用户一台DELL R740 3块2.4T硬盘组的RAID5&#xff0c;早期坏了一个盘没有及时更换&#xff0c;这次又坏了一个&#xff0c;导致整组RAID5处于数据丢失的状态&#xff0c; 2&#xff1a;该服务器装的是VMware ESXI 6.7&#xff0c;用户把3块硬盘寄过来进行数据…

程序员开发速查表

作为一名苦逼的程序员&#xff0c;在开发的过程中&#xff0c;我们总是在各种编程语言中来回穿梭&#xff0c;忙完后端整前端&#xff0c;还得做一部分的运维工作&#xff0c;忙的我们有时候忘记语法&#xff0c;忘记编写规则&#xff0c;甚至混淆。这时候我们就希望有一个综合…

「Mac畅玩鸿蒙与硬件30」UI互动应用篇7 - 简易计步器

本篇将带你实现一个简易计步器应用&#xff0c;用户通过点击按钮增加步数并实时查看步数进度&#xff0c;目标步数为 10000 步。该项目示例展示了如何使用 Progress 组件和 Button 组件&#xff0c;并结合状态管理&#xff0c;实现交互式应用。 关键词 UI互动应用计步器Button…

直播系统搭建教程安装说明

需要安装的软件(宝塔【软件商店】中查找安装): 1.PHP7.0 ~ PHP7.3 需要安装的扩展:(宝塔【PHP管理】【安装扩展】中安装) *PDO PHP Extension * MBstring PHP Extension * CURL PHP Extension * Mylsqi PHP Extension * Redis PHP Extension * fileinfo PHP Extension …

@Async注解提升Spring Boot项目中API接口并发能力

文章目录 同步调用异步调用1: 启用异步支持2: 修改 Task 类异步回调基本概念使用 Future<String>使用 CompletableFuture<String>Future<String> 和 CompletableFuture<String>区别1. 基本概念2. 主要区别同步调用 同步调用是最直接的调用方式,调用方…

对齐自治 Aligned autonomy

对于有效的产品开发&#xff0c;我们想要的自主权不是 “随心所欲” &#xff0c;而是一种自主权&#xff0c;使团队能够自由行动&#xff0c;利用他们所有的能力朝着集体成果前进。这也称为“对齐自治”。 Aligned autonomy 2x2&#xff0c;来自 Spotify 的 Henrik Kniberg 工…

Spring Boot 与 Vue 共筑二手书籍交易卓越平台

作者介绍&#xff1a;✌️大厂全栈码农|毕设实战开发&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。 &#x1f345;获取源码联系方式请查看文末&#x1f345; 推荐订阅精彩专栏 &#x1f447;&#x1f3fb; 避免错过下次更新 Springboot项目精选实战案例 更多项目…

物理验证Calibre LVS Debug案例之通过deleteEmptyModule解决LVS问题

上周帮助T12nm A55训练营学员debug一个Calibre LVS问题&#xff0c;小编觉得挺好的一个问题。这个问题之前没有遇到过&#xff0c;今天分享给大家。 数字IC后端先进工艺设计实现之TSMC 12nm 6Track工艺数字IC后端实现重点难点盘点 下图所示为Calibre LVS的报告。从报告中看到…

【系统面试篇】进程与线程类(2)(笔记)——进程调度、中断、异常、用户态、核心态

目录 一、相关面试题 1. 进程的调度算法有哪些&#xff1f; 调度原则 &#xff08;1&#xff09;先来先服务调度算法 &#xff08;2&#xff09;最短作业优先调度算法 &#xff08;3&#xff09;高响应比优先调度算法 &#xff08;4&#xff09;时间片轮转调度算法 &am…

这下热闹了:电商巨头粗暴杀入物流自动化领域

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 在全球物流行业竞争日趋白热化的今天&#xff0c;一向以互联网和电商见长的阿里巴巴集团旗下菜鸟&#xff0c;突然以一记重拳杀入物流自动化设备领域。 其自主研发的直线窄带分拣机不…

新安装的Ubuntu 24.04.1安装Python模块报错?(error: externally-managed-environment)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒📝 错误现象及原因📝 解决方案1. **创建虚拟环境**创建虚拟环境的步骤:2. **使用 pipx 管理应用**安装 `pipx`:3. **直接覆盖安装(不推荐)**4. **使用 `apt` 安装系统级包**📝 总结⚓️ 相关链接 ⚓️�…

前后端分离,Jackson,Long精度丢失

案例:后端接口放回一个Long数据 GetMapping("/testForLong")public Map<String, Object> testForLong() {Map<String, Object> map new HashMap<>();map.put("aaa", 1234567890123456789L);return map;}实际前端接收的数据 前后端数据…

【主机游戏】森林之子游戏介绍

《森林之子》是一款开放世界恐怖生存模拟游戏&#xff0c;玩家被派到孤岛上寻找失踪的亿万富翁&#xff0c;却陷入被食人生物占领的炼狱之地。他一经上线不仅饱受好评&#xff0c;还被玩家开发出来众多奇奇怪怪的玩法 https://pan.quark.cn/s/f903c978b071 当然他里边包含不限…

解线性方程组(一)

实验类型&#xff1a;●验证性实验 ○综合性实验 ○设计性实验 实验目的&#xff1a;进一步熟练掌握高斯顺序消去法解线性方程组的算法并编写程序&#xff0c;进一步熟练掌握高斯列主元消去法解线性方程组的算法并编写程序&#xff0c;提高编程能力和解算线性方程组问题的实践…

Ubuntu使用Qt虚拟键盘,支持中英文切换

前言 ​最近领导给了个需求&#xff0c;希望将web嵌入到客户端里面&#xff0c;做一个客户端外壳&#xff0c;可以控制程序的启动、停止、重启&#xff0c;并且可以调出键盘在触摸屏上使用(我们的程序虽然是BS架构&#xff0c;但程序还是运行在本地工控机上的)&#xff0c;我研…

数学建模(基于Python实现)--灰色关联分析法讲解,含案例

前言 这是去年底学数学建模老哥的建模课程笔记&#xff1b; 未来本人将陆陆续续的更新数学建模相关的一些基础算法&#xff0c;大家可以持续关注一下&#xff0c;主要在于运用&#xff1b; 提示&#xff1a;数学建模只有实战才能提升&#x1f525;​&#x1f525;​&#x1f…

jmeter结合ansible分布式压测--1数据准备

一、搭建ansible环境 ansible是基于python开发&#xff0c;通过ssh连接客户机执行任务。ansible可以批量系统配置、批量程序部署、批量运行命令等。 1、安装yum install ansible 2、检查ansible的版本:ansible --version 二、利用ansible在其他机器上准备压测数据 1、本地准…

网络:ARP的具体过程和ARP欺骗

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》《Linux》《网络》 《redis学习笔记》 文章目录 前言ARP具体过程ARP欺骗原理总结 前言 本文仅作为ARP具体过程和ARP欺骗的知识总结 硬件类型 &#xff1a;指定发送和接受ARP包的硬件类型&am…