「数组」定长滑动窗口|不定长滑动窗口 / LeetCode 2461|2958(C++)

news2024/9/22 2:08:56

目录

概述

1.定长滑动窗口

思路

复杂度

Code

2.不定长滑动窗口

思路

复杂度

Code

总结


概述

在双指针合集中,我们介绍了双指针算法:

「数组」数组双指针算法合集:二路合并|逆向合并|快慢去重|对撞指针 / LeetCode 88|26|11(C++)

从线性枚举到双指针,我们维护的变量数量从1个提升到2个,那如果我们需要维护一片连续的区域,又该使用什么办法呢?

与双指针算法维护指针指向的两个变量对应的是,滑动窗口也使用双指针,但维护的是两个指针所夹的区间[i,j]。


1.定长滑动窗口

LeetCode 2461:

给你一个整数数组 nums 和一个整数 k 。请你从 nums 中满足下述条件的全部子数组中找出最大子数组和:

  • 子数组的长度是 k,且
  • 子数组中的所有元素 各不相同 。

返回满足题面要求的最大子数组和。如果不存在子数组满足这些条件,返回 0 。

子数组 是数组中一段连续非空的元素序列。

示例 1:

输入:nums = [1,5,4,2,9,9,9], k = 3
输出:15
解释:nums 中长度为 3 的子数组是:
- [1,5,4] 满足全部条件,和为 10 。
- [5,4,2] 满足全部条件,和为 11 。
- [4,2,9] 满足全部条件,和为 15 。
- [2,9,9] 不满足全部条件,因为元素 9 出现重复。
- [9,9,9] 不满足全部条件,因为元素 9 出现重复。
因为 15 是满足全部条件的所有子数组中的最大子数组和,所以返回 15 。

思路

所谓维护两指针之间的长度为k的区域,就是利用额外的数据结构储存这段区域的特征。

定长滑动窗口的流程无非是两步:

①展开窗口并创建初始数据结构

②移动窗口并维护过程数据结构

对于本题,我们使用两个数据结构维护区间特征:哈希表和一个单变量sum。不同的题目自有不同的要求。

第一步:先展开窗口到k的大小,我们创建哈希表储存其中数字出现的次数。

当窗口长度达到k时,我们的初始数据结构哈希表也就创建好了。

unordered_map<int,int>cnt;
const int n=nums.size();
long long ans=0,sum=0;
for(int i=0;i<k;i++){
    cnt[nums[i]]++;
    sum+=nums[i];
}
if(cnt.size()==k)ans=sum;

一个值得注意的点是,如果哈希表的键值对数量(也就是哈希表的size)正好是k的话,那么这个初始展开的窗口就是有效的,应该令ans=sum,表示我们考虑此为第一种可能得答案。

第二步:窗口开始滑动,哈希表和sum抛出不需再维护的特征。

*注意*:在一轮循环开始是,j位置是窗口右边界(包含j)移动到的位置,因此每轮循环维护的区域是[j-k+1,j]。

抛出j-k,即左边界外的那个位置,当哈希表维护的对应值为0时,我们使用erase彻底将其在哈希表中抹除,以免无效键值对污染哈希表的size。

for(int j=k;j<n;j++){
    cnt[nums[j-k]]--,cnt[nums[j]]++;
    if(!cnt[nums[j-k]])cnt.erase(nums[j-k]);
    sum=sum-nums[j-k]+nums[j];
    if(cnt.size()==k)ans=max(ans,sum);
}
return ans;

时时更新ans,维护其最大性质。 

复杂度

时间复杂度:O(n) 

Code

class Solution {
public:
    long long maximumSubarraySum(vector<int>& nums, int k) {
        unordered_map<int,int>cnt;
        const int n=nums.size();
        long long ans=0,sum=0;
        for(int i=0;i<k;i++){
            cnt[nums[i]]++;
            sum+=nums[i];
        }
        if(cnt.size()==k)ans=sum;
        for(int j=k;j<n;j++){
            cnt[nums[j-k]]--,cnt[nums[j]]++;
            if(!cnt[nums[j-k]])cnt.erase(nums[j-k]);
            sum=sum-nums[j-k]+nums[j];
            if(cnt.size()==k)ans=max(ans,sum);
        }
        return ans;
    }
};

2.不定长滑动窗口

LeetCode 2958:

给你一个整数数组 nums 和一个整数 k 。

一个元素 x 在数组中的 频率 指的是它在数组中的出现次数。

如果一个数组中所有元素的频率都 小于等于 k ,那么我们称这个数组是  数组。

请你返回 nums 中 最长好 子数组的长度。

子数组 指的是一个数组中一段连续非空的元素序列。

示例 1:

输入:nums = [1,2,3,1,2,3,1,2], k = 2
输出:6
解释:最长好子数组是 [1,2,3,1,2,3] ,值 1 ,2 和 3 在子数组中的频率都没有超过 k = 2 。[2,3,1,2,3,1] 和 [3,1,2,3,1,2] 也是好子数组。
最长好子数组的长度为 6 。

思路

不定长窗口和定长窗口的滑动本质上并无不同,尽管它看起来更难。

仍然,我们使用数据结构维护区间特征,只不过这次,左边界移动的条件是通过访问数据结构来达到的

具体的,我们会使用外层for循环控制右边界j的移动,而左边界的移动i则有内层while循环来实现。while循环的条件取决于维护[i,j]特征的数据结构,当特征不满足题意时,i左移抛出最左侧特征,并更新数据结构,一直循环到满足题意为止,则我们得到了[i,j]有效窗口区。

不定长滑动窗口的流程可以直接套模板,用伪代码展现的话,应该是这样的:

{

     某数据结构 data;

     int ans=0;

     for(j遍历nums){

         data加入nums[j]特征;

         while(i<j&&data不满足题设条件)数据结构抛出nums[i],i++;

         if(data满足题设条件)更新ans;

      }

}

对于本题,数据结构data应为一张记录了元素出现次数的哈希表。

同时,所谓“data不满足题设条件”只需要研究nums[j]即可,因为对于j之前的元素,上一次外层for循环会保证其满足题设条件。

*注意*:更新ans时要确保当前满足题设条件,因为i==j也会退出while循环。

复杂度

时间复杂度:O(n) 

复杂度分析:

时间分析: {

指针j共遍历数组一次,复杂度为O(n)

指针i虽在内层循环,但只前进不倒退,复杂度为O(n)

故整体复杂度为O(n)

}

Code

class Solution {
public:
    int maxSubarrayLength(vector<int>& nums, int k) {
        unordered_map<int,int>hash;
        const int n=nums.size();
        int ans=0;
        for(int i=0,j=0;j<n;j++){
            hash[nums[j]]++;
            while(i<j&&hash[nums[j]]>k)hash[nums[i++]]--;
            if(hash[nums[j]]<=k)ans=max(ans,j-i+1);
        }
        return ans;
    }
};

总结

滑动窗口是一类经典的双指针问题,它会借用额外的存储结构来维护一段连续的子数组。

但需要注意的是,一旦出现负数,它会变得极其被动,这是由于我们期望滑动窗口维护的区间特征总是右增左减的。

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

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

相关文章

网络丢包定位记录(三)

网络IP层丢包 接口ip地址配置丢包 1. 本机服务不通&#xff0c;检查lo接口有没有配置地址是127.0.0.1&#xff1b; 2 .本机接收失败&#xff0c; 查看local路由表&#xff1a;ip r show table local|grep 子机ip地址&#xff1b;这种丢包一般会出现在多IP场景&#xff0c;子…

robomimic应用教程(一)——模型训练

Robomimic使用集中式配置系统来指定所有级别的(超)参数 本文介绍了配置&#xff08;推荐&#xff09;和启动训练运行的两种方法 目录 一、使用config json&#xff08;推荐&#xff09; 二、在代码中构造一个配置对象 三、查看运行结果 1. 实验结果会存在一个固定文件夹中…

S-Clustr-Simple 飞机大战:骇入现实的建筑灯光游戏

项目地址:https://github.com/MartinxMax/S-Clustr/releases Video https://www.youtube.com/watch?vr3JIZY1olro 飞机大战 这是一个影子集群的游戏插件&#xff0c;可以将游戏画面映射到现实的设备&#xff0c;允许恶意控制来完成游戏。亦或者设备部署在某建筑物中,来控制…

超实用的 Typora 插件

&#x1f33c;&#x1f4da;Typora 是一款高效、易用且跨平台的 Markdown 编辑器和阅读器&#xff0c;其具有小巧、快速、实时预览等特点&#xff0c;非常受大家的欢迎。今天给大家推荐一款如虎添翼的 Typora 插件(Typora Plugin)&#xff0c;它可以通过插件增强 Typora 的功能…

C++入门(03)萌新问题多(二)

文章目录 1. VS2022 控制台输出中文时&#xff0c;变成了一堆“&#xff1f;”1.1 字体、语言设置1.2 在程序中指定控制台编码1.3 修改注册表&#xff08;只能说试试吧&#xff09; 1. VS2022 控制台输出中文时&#xff0c;变成了一堆“&#xff1f;” 问题如下&#xff0c;Vi…

解决uniapp开发的app,手机预览,上下滑动页面,页面出现拉伸,抖动的效果问题,

在pages.json文件里“globalStyle”下面的"app-plus"里加入"bounce": "none"即可 "app-plus": { "bounce": "none", //关闭窗口回弹效果 }

[Leetcode] 227.基本计算器

标题&#xff1a;[Leetcode] 227.基本计算器 个人主页&#xff1a;水墨不写bug &#xff08;图片来源于网络&#xff09; // _ooOoo_ // // o8888888o // // …

linux 获取指定端口的PID netsat awk

使用netstat -ntpl 获取指定端口的PID #获取端口19000对应的PID netstat -ntpl | grep 19000 | awk {print $NF} | awk -F/ {print $1}

vcs/verdi常用命令(持续更新)

1. 操作rtl 1.1 加载rtl命令 verdi -dbdir simv.daidir的目录 1.2 显示某时刻rtl的值 首先鼠标左键在波形上选中某个特定时刻&#xff0c;然后鼠标选中rtl代码文件&#xff0c;按x就会显示&#xff0c;再按x就会退出显示。 1.3 查找字符串 按/ 1.4 vcs将rtl的信号加载到…

mockito+junit搞定单元测试(2h)

一&#xff0c;简介 1.1 单元测试的特点 配合断言使用(杜绝 System.out )可重复执行不依赖环境不会对数据产生影响spring 的上下文环境不是必须的一般都需要配合 mock 类框架来实现 1.2 mock 类框架使用场景 要进行测试的方法存在外部依赖(如 db, redis, 第三方接口调用等)…

HashMap扩容时机是插入前还是插入后?

结论 不管是HashMap还是ConcurrentHashMap都是插入后。 过程为&#xff1a; 先计算哈希值。对应的哈希槽插入数据&#xff0c;决定是红黑树还是链表插入完毕才计算是否需要扩容&#xff0c;假如需要则扩容 源码 源码如下&#xff1a; 其中addCount方法里面写入扩容。

如何设置 Django 错误邮件通知 ?

Django 是一个强大的 web 框架&#xff0c;非常适合那些想要完美快速完成任务的人。它有许多内置的工具和特性&#xff0c;一个有用的特性是 Django 可以在出现错误时发送电子邮件提醒。这对开发人员和管理员非常有用&#xff0c;因为如果出现问题&#xff0c;他们会立即得到通…

STM32F407单片机编程入门(十二) FreeRTOS实时操作系统详解及实战含源码

文章目录 一.概要二.什么是实时操作系统三.FreeRTOS的特性四.FreeRTOS的任务详解1.任务函数定义2.任务的创建3.任务的调度原理 五.CubeMX配置一个FreeRTOS例程1.硬件准备2.创建工程3.调试FreeRTOS任务调度 六.CubeMX工程源代码下载七.小结 一.概要 FreeRTOS是一个迷你的实时操…

智慧校园建设解决方案建设系统简介

一、建设背景 1.1 政策背景 1.2 班牌的演变 1.3 建设愿景 二、 智慧班牌简介 三、智慧班牌系统 3.1 系统概述 3.2 软件平台功能交互简介 3.2.1 智慧班牌与管理平台间的功能关联 3.2.2 手机客户端&#xff08;管理员、教师、家长端&#xff09; 3.2.3 手机客户端&#x…

数据采集与预处理,前后端结合案例(有代码),Python连接MySQL,对MySQL的增删改查

Python对MySQL的增删改查 通过Python连接MySQL """连接MySQL数据库&#xff0c;并进行增删改查&#xff0c;同时查询了MySQL版本号&#xff0c;并做了动态注册的账号&#xff0c;实现过程&#xff1a;先向userinfo当中添加account、password新字段&#xff0c…

数据结构:内部排序

文章目录 1. 前言1.1 什么是排序&#xff1f;1.2 排序的稳定性1.3 排序的分类和比较 2. 常见的排序算法3. 实现常见的排序算法3.1 直接插入排序3.2 希尔排序3.3 直接选择排序3.4 堆排序3.5 冒泡排序3.6 快速排序3.6.1 hoare思想3.6.2 挖坑法3.6.3 lomuto前后指针法3.6.4 非递归…

软考(中级-软件设计师)计算机系统篇(0921)

I 计算机系统知识 一、考纲要求 数值及其转换 二进制、十进制和十六进制等常用数制及其相互转换 计算机内数据的表示 数值的表示&#xff08;原码、反码、补码、移码表示&#xff0c;整数和实数的机内表示&#xff0c;精度和溢出&#xff09;非数值表示&#xff08;字符和汉字…

AI直播新浪潮:无人视频自动直播,出圈再造辉煌,创业者首选!

AI直播新浪潮:无人视频自动直播&#xff0c;出圈再造辉煌&#xff0c;创业者首选&#xff01; 在数字化浪潮的汹涌澎湃中&#xff0c;AI技术正以前所未有的速度重塑着各行各业的边界&#xff0c;而直播行业作为数字内容消费的前沿阵地&#xff0c;正迎来一场由AI驱动的深刻变革…

MQ(RabbitMQ)笔记

初识MQ 同步调用优缺点 异步调用优缺点 总结&#xff1a; 时效性要求高&#xff0c;需要立刻得到结果进行处理--->同步调用 对调用结果不关心&#xff0c;对性能要求高&#xff0c;响应时间短--->异步调用

2024年华为杯-研赛F题论文问题一二讲解+代码分享

X射线脉冲星光子到达时间建模 摘要 脉冲星是一类高速自转的中子星&#xff0c;其自转形成规律性脉冲信号&#xff0c;类似于“宇宙中的灯塔”&#xff0c;因此被认为是极为精确的时钟。X射线脉冲星导航利用脉冲星信号为航天器提供时间和空间参考。通过比较脉冲信号到达航天器…