滑动窗口--(上篇)

news2024/10/4 19:07:58

滑动窗口

在这里插入图片描述

长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target

找出该数组中满足其总和大于等于 target 的长度最小的

子数组

[numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度**。**如果不存在符合条件的子数组,返回 0

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

示例 2:

输入:target = 4, nums = [1,4,4]
输出:1

示例 3:

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

提示:

  • 1 <= target <= 109
  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 105

题目解析
在这里插入图片描述

这里的关键点在于正整数,可以对代码进行优化,在单调性方面

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

问题1:什么是“滑动窗口”?

“滑动窗口”是指同向双指针,像窗户一样移动的算法

问题2:怎么使用滑动窗口?

step 1:让左右指针指向同一块地方

step 2:进入窗口,左指针不动,右指针移动

step 3:判断是否需要更新结果或者出窗口,更新结果要先出窗口,在进行判断

问题3: 为什么滑动窗口的方法是正确的?

利用单调性,能够规避很多没有必要的枚举行为,我们需要先用暴力解法去了解,因为我们得到优化的解法,这道题题干说明了是正整数,所以太长了一定是大于目标值

问题4:时间复杂度怎么样?

看下面的代码两层循环可能会以为是O(N2),但是实际并不是,是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;
    }
};

更详细来说,

解法⼀(暴⼒求解)(会超时):

算法思路:

「从前往后」枚举数组中的任意⼀个元素,把它当成起始位置。然后从这个「起始位置」开始,然 后寻找⼀段最短的区间,使得这段区间的和「⼤于等于」⽬标值。

将所有元素作为起始位置所得的结果中,找到「最⼩值」即可

算法代码:

class Solution {
public:
 int minSubArrayLen(int target, vector<int>& nums) {
 // 记录结果
int ret = INT_MAX;
 int n = nums.size();
 // 枚举出所有满⾜和⼤于等于 target 的⼦数组[start, end]
 // 由于是取到最⼩,因此枚举的过程中要尽量让数组的⻓度最⼩
 // 枚举开始位置
 for (int start = 0; start < n; start++)
 {
 int sum = 0; // 记录从这个位置开始的连续数组的和
 // 寻找结束位置
 for (int end = start; end < n; end++)
 {
 sum += nums[end]; // 将当前位置加上
 
 if (sum >= target) // 当这段区间内的和满⾜条件时
 {
 // 更新结果,start 开头的最短区间已经找到
 ret = min(ret, end - start + 1);
 break;
 }
 }
 }
 // 返回最后结果
 return ret == INT_MAX ? 0 : ret;
 }
};

解法⼆(滑动窗⼝):

算法思路:

由于此问题分析的对象是「⼀段连续的区间」,因此可以考虑「滑动窗⼝」的思想来解决这道题。

让滑动窗⼝满⾜:从 i 位置开始,窗⼝内所有元素的和⼩于 target (那么当窗⼝内元素之和 第⼀次⼤于等于⽬标值的时候,就是 i 位置开始,满⾜条件的最⼩⻓度)。

做法:将右端元素划⼊窗⼝中,统计出此时窗⼝内元素的和:

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

▪ 如果窗⼝内元素之和不满⾜条件: right++ ,另下⼀个元素进⼊窗⼝。

为何滑动窗⼝可以解决问题,并且时间复杂度更低?

▪ 这个窗⼝寻找的是:以当前窗⼝最左侧元素(记为 left1 )为基准,符合条件的情况。也 就是在这道题中,从 left1 开始,满⾜区间和 sum >= target 时的最右侧(记为 right1 )能到哪⾥。

▪ 我们既然已经找到从 left1 开始的最优的区间,那么就可以⼤胆舍去 left1 。但是如 果继续像⽅法⼀⼀样,重新开始统计第⼆个元素( left2 )往后的和,势必会有⼤量重复 的计算(因为我们在求第⼀段区间的时候,已经算出很多元素的和了,这些和是可以在计算 下次区间和的时候⽤上的)。

▪ 此时, rigth1 的作⽤就体现出来了,我们只需将 left1 这个值从 sum 中剔除。从 right1 这个元素开始,往后找满⾜ left2 元素的区间(此时 right1 也有可能是满 ⾜的,因为 left1 可能很⼩。 sum 剔除掉 left1 之后,依旧满⾜⼤于等于 target )。这样我们就能省掉⼤量重复的计算。

▪ 这样我们不仅能解决问题,⽽且效率也会⼤⼤提升.

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

无重复字符的最长字串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长

子串

的长度。

示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

提示:

  • 0 <= s.length <= 5 * 104
  • s 由英文字母、数字、符号和空格组成

在这里插入图片描述

在这里插入图片描述

代码如下:

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

        }
        return ret;
    }
};

解法⼀(暴⼒求解)(不会超时,可以通过):

算法思路:

枚举「从每⼀个位置」开始往后,⽆重复字符的⼦串可以到达什么位置。找出其中⻓度最⼤的即 可。

在往后寻找⽆重复⼦串能到达的位置时,可以利⽤「哈希表」统计出字符出现的频次,来判断什么 时候⼦串出现了重复元素。

算法代码:

class Solution {
public:
 int lengthOfLongestSubstring(string s) {
 int ret = 0; // 记录结果
 int n = s.length();
 // 1. 枚举从不同位置开始的最⻓重复⼦串
 // 枚举起始位置
 for (int i = 0; i < n; i++)
 {
// 创建⼀个哈希表,统计频次
 int hash[128] = { 0 };
 
 // 寻找结束为⽌
 for (int j = i; j < n; j++)
 {
 hash[s[j]]++; // 统计字符出现的频次
 if (hash[s[j]] > 1) // 如果出现重复的
 break;
 
 // 如果没有重复,就更新 ret
 ret = max(ret, j - i + 1);
 }
 }
 // 2. 返回结果
 return ret;
 }
};

解法⼆(滑动窗⼝):

算法思路:

研究的对象依旧是⼀段连续的区间,因此继续使⽤「滑动窗⼝」思想来优化。

让滑动窗⼝满⾜:窗⼝内所有元素都是不重复的。

做法:右端元素 ch 进⼊窗⼝的时候,哈希表统计这个字符的频次:

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

▪ 如果没有超过 1 ,说明当前窗⼝没有重复元素,可以直接更新结果

最大连续1的个数

给定一个二进制数组 nums 和一个整数 k,如果可以翻转最多 k0 ,则返回 数组中连续 1 的最大个数

示例 1:

输入:nums = [1,1,1,0,0,0,1,1,1,1,0], K = 2
输出:6
解释:[1,1,1,0,0,1,1,1,1,1,1]
粗体数字从 0 翻转到 1,最长的子数组长度为 6。

示例 2:

输入:nums = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], K = 3
输出:10
解释:[0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1]
粗体数字从 0 翻转到 1,最长的子数组长度为 10。

提示:

  • 1 <= nums.length <= 105
  • nums[i] 不是 0 就是 1
  • 0 <= k <= nums.length
    在这里插入图片描述

在这里插入图片描述

解法(滑动窗⼝):

算法思路:
不要去想怎么翻转,不要把问题想的很复杂,这道题的结果⽆⾮就是⼀段连续的 1 中间塞了 k 个 0 嘛。

因此,我们可以把问题转化成:求数组中⼀段最⻓的连续区间,要求这段区间内 0 的个数不超 过 k 个。

既然是连续区间,可以考虑使⽤「滑动窗⼝」来解决问题。

算法流程:

a. 初始化⼀个⼤⼩为 2 的数组就可以当做哈希表 hash 了;初始化⼀些变量 left = 0 , right = 0 , ret = 0 ;

b. 当 right ⼩于数组⼤⼩的时候,⼀直下列循环:

i. 让当前元素进⼊窗⼝,顺便统计到哈希表中;

ii. 检查 0 的个数是否超标:

• 如果超标,依次让左侧元素滑出窗⼝,顺便更新哈希表的值,直到 0 的个数恢复正 常;

iii. 程序到这⾥,说明窗⼝内元素是符合要求的,更新结果;

iv. right++ ,处理下⼀个元素;

c. 循环结束后, ret 存的就是最终结果。

代码如下:

class Solution {
public:
    int longestOnes(vector<int>& nums, int k) {
     int ret=0;
     for(int left=0,right=0,zero=0;right<nums.size();right++)
     {
        if(nums[right]==0) zero++;//进窗口
        while(zero>k)//判断
            if(nums[left++]==0) zero--;//出窗口
            ret=max(ret,right-left+1);//更新结果
     }
     return ret;
    }
};

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

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

相关文章

LLM Visualization

Brendan Bycroft的网站&#xff0c;提供了交互式的可视化工具&#xff0c;展示了大型语言模型&#xff08;LLMs&#xff09;的内部机制 通过这个 链接 https://bbycroft.net/llm 访问 借助这个交互可视化&#xff0c;能够加深对模型结构和行为的了解

国庆更新|芒果YOLOv8改进181:即插即用,最新注意力机制EMA:具有跨空间学习的高效多尺度注意力模块,ICCASSP论文

💡本篇内容:芒果YOLOv8改进135:最新注意力机制EMA:即插即用,具有跨空间学习的高效多尺度注意力模块,ICCASSP 论文 **EMA|具有跨空间学习的高效多尺度注意力模块 | 即插即用 该模块通常包括多个并行的注意力子模块,每个子模块关注于输入数据的不同尺度或分辨率。这些子模块…

【SpringCloud】优雅实现远程调⽤-OpenFeign

OpenFeign 1. RestTemplate存在问题2. OpenFeign介绍Spring Cloud Feign 3. 代码获取 1. RestTemplate存在问题 观察咱们远程调⽤的代码 RequestMapping("/{orderId}")public OrderInfo getOrderInfoById(PathVariable("orderId") Integer id) {OrderInfo…

Ascend C 自定义算子开发:高效的算子实现

Ascend C 自定义算子开发&#xff1a;高效的算子实现 在 Ascend C 平台上&#xff0c;开发自定义算子能够充分发挥硬件的性能优势&#xff0c;帮助开发者针对不同的应用场景进行优化。本文将以 AddCustom 算子为例&#xff0c;介绍 Ascend C 中自定义算子的开发流程及关键技术…

Java中for循环控制

for循环控制 基本语法说明执行流程注意事项练习 基本语法 for(循环变量初始化;循环条件;循环遍历迭代){循环操作&#xff08;可以多条语句&#xff09;; }说明 1.for关键字&#xff0c;表示循环控制 2.for有四要素&#xff1a;&#xff08;1&#xff09;循环变量初始化 &…

Python+Matplotlib奇偶函数简单示例可视化

偶函数 定义&#xff1a;如果对于定义域内的任意 x&#xff0c;都有 f(-x) f(x)&#xff0c;则称 f(x) 为偶函数。 特点&#xff1a;偶函数的图像关于 y 轴对称。 奇函数 定义&#xff1a;如果对于定义域内的任意 x&#xff0c;都有 f(-x) -f(x)&#xff0c;则称 f(x) 为奇函…

【计算机网络】详解UDP协议格式特点缓冲区

一、UDP 协议端格式 16 位 UDP 长度, 表示整个数据报(UDP 首部UDP 数据)的最大长度&#xff1b;如果16位UDP检验和出错&#xff0c;报文会被直接丢弃。 1.1、检验和出错的几种常见情况 数据传输过程中的比特翻转&#xff1a;在数据传输过程中&#xff0c;由于物理介质或网络设…

COMSOL金属氢化物吸氢过程膨胀、应力

话不多说&#xff0c;先上效果图。事先说明&#xff1a;由于做吸氢膨胀和应力相关的文献很少&#xff0c;而且文献中很多细节、参数的地方也没怎么说&#xff0c;因此有些地方是笔者按自己理解编的&#xff0c;算是抛砖引玉&#xff0c;希望能给读者带来些许思路启发&#xff0…

【Simulink仿真】混合储能系统光储直流微网下垂控制

摘要 混合储能系统&#xff08;HESS&#xff09;结合光伏发电和储能技术&#xff0c;已成为提高直流微网系统稳定性和能效的有效手段。本文基于Simulink平台&#xff0c;仿真研究了光储直流微网中的下垂控制策略。仿真模型涵盖了电池储能和超级电容储能&#xff0c;采用下垂控…

11. 异步编程

计算机的核心部分&#xff0c;即执行构成我们程序的各个步骤的部分&#xff0c;称为处理器。我们迄今为止看到的程序都会让处理器忙个不停&#xff0c;直到它们完成工作。像操作数字的循环这样的程序的执行速度几乎完全取决于计算机处理器和内存的速度。但是&#xff0c;许多程…

【C++差分数组】2406. 将区间分为最少组数|1731

本文涉及知识点 C差分数组 LeetCode2406. 将区间分为最少组数 给你一个二维整数数组 intervals &#xff0c;其中 intervals[i] [lefti, righti] 表示 闭 区间 [lefti, righti] 。 你需要将 intervals 划分为一个或者多个区间 组 &#xff0c;每个区间 只 属于一个组&#…

HTB:Included[WriteUP]

目录 连接至HTB服务器并启动靶机 1.What service is running on the target machine over UDP? 2.What class of vulnerability is the webpage that is hosted on port 80 vulnerable to? 3.What is the default system folder that TFTP uses to store files? 4.Whic…

TCP --- 确认应答机制以及三次握手四次挥手

序言 在前一篇文章中&#xff0c;我们介绍了 UDP协议 (点击查看)&#x1f448;&#xff0c;该协议给我们的感觉就两个字 — 简单&#xff0c;只是将我们的数据进行简单的添加报头然后发送。当然使用起来虽然简单&#xff0c;但是否能送到目的地&#xff0c;那就要看网络的状态了…

【算法系列-链表】链表相交 环形链表II

【算法系列-链表】链表相交&环形链表 文章目录 【算法系列-链表】链表相交&环形链表1. 链表相交1.1 思路分析&#x1f3af;1.2 解题过程&#x1f3ac;1.3 代码示例&#x1f330; 2. 环形链表II2.1 思路分析&#x1f3af;2.2 代码示例&#x1f330; 1. 链表相交 【题目…

C/C++:内存管理

文章目录 前言一、内存分区1. 内存划分情况2. 最大内存计算 二、malloc/calloc/realloc 与 free1. malloc2. calloc3. realloc4. free5. 差异对比6. 失败处理 三、内存分配题目1. 题目2. 内存区域划分 四、C内存管理方式1. new 与 delete2. new/delete操作内置类型3. new和dele…

数据科学基础复习(简)

可视化、数据可视化 在狭义上&#xff0c;数据可视化是与信息可视化&#xff0c;科学可视化和可视分析学平行的概念&#xff0c;而在广义上数据可视化可以包含这3类可视化技术。 数据科学的主要任务 数据科学研究目的与任务 大数据及其运动规律的揭示从数据到智慧的转化数据…

【web安全】——命令执行漏洞/代码执行漏洞

1.命令执行漏洞 1.1漏洞原理 应用有时需要调用一些执行系统命令的函数&#xff0c;如PHP中的system、exec、shell_exec、passthru、popen、proc_popen等&#xff0c;当用户能控制这些函数的参数&#xff0c;并且开发人员对这个参数没有严格的过滤时就可以将恶意系统命令拼接到…

仿RabbitMQ实现消息队列服务端(二)

文章目录 ⽹络通信协议设计信道管理模块连接管理模块服务器模块实现 ⽹络通信协议设计 其中⽣产者和消费者都是客⼾端&#xff0c;它们都需要通过⽹络和BrokerServer进⾏通信。具体通信的过程我们使⽤Muduo库来实现&#xff0c;使⽤TCP作为通信的底层协议&#xff0c;同时在这个…

中级软件设计师:一文搞懂下午第二题——数据库设计

中级软件设计师&#xff1a;一文搞懂下午第二题——数据库设计 1. 数据库设计过程1.1 ER模型1.1.0 浅谈UML1.1.1 实体&#xff08;Entity&#xff09;1.1.2 联系1.1.3 联系类型1.1.4 实体间的联系模型 1.2 属性&#xff08;Attribute&#xff09;1.3 关系&#xff08;Relations…

Python案例--动态奖金计算(个税计算)

在企业财务管理中&#xff0c;员工的奖金计算是一项关键任务&#xff0c;它直接关系到员工的积极性和忠诚度。一个合理的奖金制度能够激励员工更好地完成工作&#xff0c;提高企业的整体竞争力。本文将通过Python编程语言&#xff0c;详细探讨如何根据企业利润计算员工的奖金。…