当前位置: 首页 > news >正文

算法【滑动窗口】

滑动窗口指的是维持左、右边界都不回退的一段范围,来求解很多子数组(串)的相关问题。

滑动窗口的关键是找到范围和答案指标之间的单调性关系(类似贪心)。

滑动过程:滑动窗口可以用简单变量或者结构来维护信息。

求解大流程:求子数组在每个位置开头或结尾情况下的答案(开头还是结尾在于个人习惯)。

下面通过几个题目加深理解。

题目一

测试链接:https://leetcode.cn/problems/minimum-size-subarray-sum/

分析:如果判断左右边界不回退是应用滑动窗口的关键。设滑动窗口代表以right为结尾的满足条件的最短子数组。假设存在一个满足条件的最短子数组,那么,将left回退,也就是左移也一定会满足条件,而我们是要求最短的子数组,所以确定了right的情况下,left是不会回退的。然后right继续右移,寻找更多情况。直到找到满足条件的子数组,再判断left是否需要右移。遍历数组即可找到最短子数组的长度。代码如下。

class Solution {
public:int minSubArrayLen(int target, vector<int>& nums) {int ans = 100005;int left = 0, right = 0;int sum = 0;for(;right < nums.size();++right){sum += nums[right];if(sum >= target){while (sum - nums[left] >= target){sum -= nums[left++];}ans = ans < (right - left + 1) ? ans : (right - left + 1);}}return ans == 100005 ? 0 : ans;}
};

其中,将ans初始化为100005是因为nums数组最长为100000,只要比这个数大就行。

题目二

测试链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters/

分析:设滑动窗口为以right为结尾的符合条件的最长子串。可以通过一个数组记录每个符号最晚出现的下标。当right来到一个字符的时候,把left置为right最晚出现位置下标加1和left的最大值,这时候ans和right-left+1取最大值,然后更新right处字符最晚出现的下标。遍历数组即可得到最长符合条件的子串长度。代码如下。

class Solution {
public:int lengthOfLongestSubstring(string s) {vector<int> position;int ans = 0;position.assign(256, -1);for(int left = 0, right = 0;right < s.size();++right){left = left > (position[s[right]] + 1) ? left : (position[s[right]] + 1);ans = ans > (right - left + 1) ? ans : (right - left + 1);position[s[right]] = right;}return ans;}
};

其中,position存储各字符最晚出现下标,初始化为-1,方便对一个未出现过的字符更新left值时,将left更新为0。

题目三

测试链接:https://leetcode.cn/problems/minimum-window-substring/

分析:设滑动窗口为以right为结尾的子串。可以通过一个数组记录,每个字符串t中的每种字符的需要被覆盖的个数,同时用一个变量记录总的需要被覆盖个数。当覆盖个数达到要求时,开始调整left。调整后计算ans和right-left+1的最小值。遍历数组即可求得符合条件的最小子串的长度。代码如下。

class Solution {
public:string minWindow(string s, string t) {if(s.size() < t.size()){return "";}vector<int> cnt;int ans = 100005;int l;int count = -t.size();cnt.assign(256, 0);for(int i = 0;i < t.size();++i){--cnt[t[i]];}for(int left = 0, right = 0;right < s.size();++right){if(cnt[s[right]] < 0){count++;}cnt[s[right]]++;if(count >= 0){while (cnt[s[left]] - 1 >= 0){cnt[s[left++]]--;}if((right - left + 1) < ans){ans = (right - left + 1);l = left;}}}return ans == 100005 ? "" : s.substr(l, ans);}
};

其中,ans设为100005的原因之前说过,cnt数组用来记录每种字符需要被覆盖的次数,当大于等于0时代表对此种字符覆盖完毕,count是总的用来记录覆盖完成与否。

题目四

测试链接:https://leetcode.cn/problems/gas-station/

分析:设滑动窗口为以begin为开头的能否走完全程。从begin开始,只要总油量小于0,begin就前移。直到走下去,发现距离等于数组长度,就可以返回begin。如果遍历完数组没有返回begin,则返回-1。代码如下。

class Solution {
public:int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {int length = gas.size();for(int begin = 0, end = 0, soil = 0, distance = 0; begin < length;++begin){while (soil >= 0){if(distance == length){return begin;}end = (begin + distance++) % length;soil += (gas[end] - cost[end]);}soil -= (gas[begin] - cost[begin]);distance--;}return -1;}
};

题目五

测试链接:https://leetcode.cn/problems/replace-the-substring-for-balanced-string/

分析:设滑动窗口为以left为开头,最少需要多长的自由变换的区间,可以符合条件。就是说除了自由变换区间中的字符,其他字符不动,只变换自由变换区间中的字符就可以使这个字符串满足条件。确定下left和right之后,更新ans,右移left,而right并不需要回退。这是因为如果left到right区间是自由变换区间,那么left到right+1区间也是自由变换区间。同理,如果left到right-1区间不是自由变换区间,则left+1到right-1区间也不是自由变换区间。所以当left右移时,right并不需要回退。代码如下。

class Solution
{
public:int cnt[4] = {0};bool ok(int num){for (int i = 0; i < 4; ++i){if (cnt[i] > num){return false;}}return true;}int get_index(char ch){switch (ch){case 'Q':return 0;case 'W':return 1;case 'E':return 2;case 'R':return 3;}return -1;}int balancedString(string s){int length = s.size();int num = (length >> 2);for (int i = 0; i < length; ++i){++cnt[get_index(s[i])];}if (cnt[0] == num && cnt[1] == num && cnt[2] == num && cnt[3] == num){return 0;}int ans = length;for (int left = 0, right = 0; left < length; ++left){while (!ok(num) && right < length){--cnt[get_index(s[right++])];}if (ok(num)){ans = ans < (right - left) ? ans : (right - left);}++cnt[get_index(s[left])];}return ans;}
};

其中,cnt数组是用来记录除滑动窗口外每种字符的个数,ok方法判断当前滑动窗口是否可以作为自由变换区间。注意,代码中区间为左闭右开,即[left, right)。

题目六

测试链接:https://leetcode.cn/problems/subarrays-with-k-different-integers/

分析:这个题可以将其分解出来,我们可以写一个f方法用来计算子数组中小于等于k种整数的子数组个数。而要求题目的解只需要f(k)-f(k-1)即可。而分解出来的f方法则可以分析出单调性使用滑动窗口求解。代码如下。

class Solution {
public:vector<int> cnt;int f(int num, vector<int>& nums){cnt.assign(20001, 0);int ans = 0;int count = 0;for(int left = 0, right = 0;right < nums.size();++right){if(cnt[nums[right]]++ == 0){++count;}while (count > num){if(--cnt[nums[left++]] == 0){--count;}}ans += (right - left + 1);}return ans;}int subarraysWithKDistinct(vector<int>& nums, int k) {return f(k, nums) - f(k-1, nums);}
};

其中,count为种类数。

题目七

测试链接:https://leetcode.cn/problems/longest-substring-with-at-least-k-repeating-characters/

分析:此题也是一样的,如果直接求解,单调性很难分析出来。我们可以将其分解为子串中只能有i种字符,每种字符必须出现的次数必须大于等于k。只需将i从1到26遍历一次,即可找到符合条件的最大子串长度。代码如下。

class Solution {
public:vector<int> cnt;int longestSubstring(string s, int k) {int ans = 0;int length = s.size();for(int i = 1;i <= 26;++i){cnt.assign(26, 0);for(int left = 0, right = 0, kind = 0, match = 0;right < length;++right){if(cnt[s[right] - 'a'] == 0){++kind;}if(cnt[s[right] - 'a'] == k-1){++match;}++cnt[s[right] - 'a'];while (kind > i){--cnt[s[left] - 'a'];if(cnt[s[left] - 'a'] == k-1){--match;}if(cnt[s[left] - 'a'] == 0){--kind;}++left;}if(match == i){ans = ans > (right - left + 1) ? ans : (right - left + 1);}}}return ans;}
};

其中,kind为[left, right]区间字符种类数,match为区间中大于等于k的字符种类数。

相关文章:

算法【滑动窗口】

滑动窗口指的是维持左、右边界都不回退的一段范围&#xff0c;来求解很多子数组&#xff08;串&#xff09;的相关问题。 滑动窗口的关键是找到范围和答案指标之间的单调性关系&#xff08;类似贪心&#xff09;。 滑动过程&#xff1a;滑动窗口可以用简单变量或者结构来维护…...

【RISC-V设计-06】- RISC-V处理器设计K0A之ALU

【RISC-V设计-06】- RISC-V处理器设计K0A之ALU 文章目录 【RISC-V设计-06】- RISC-V处理器设计K0A之ALU1.简介2.顶层设计3.内部结构4.端口说明5.操作码说明6.设计代码7.总结 1.简介 算术逻辑单元&#xff08;Arithmetic Logic Unit&#xff0c;简称 ALU&#xff09;是计算机中…...

MyIP:强大且简单好用!

在这个数字化的时代&#xff0c;IP地址就像是我们的网络身份证。各位在日常的工作中&#xff0c;肯定会会遇到需要和 IP 地址相关的需求。 今天和大家聊一聊一个非常好用的开源 IP 工具项目 - MyIP。 简介 MyIP一个开源IP工具箱&#xff0c;提供了一系列的网络检测工具&…...

Redis作为缓存,如何与MySql的数据进行同步?

允许延时一致的业务 概念 采用异步通知使用MQ作为中间件&#xff0c;更新数据之后通知缓存删除利用canal中间件&#xff0c;不需要修改业务代码&#xff0c;伪装成Mysql的一个从节点&#xff0c;canal通过读取binlog数据更新缓存 强一致性业务 概念 采用Redission提供的读写锁…...

Android 通知栏推送功能

Android 通知栏推送功能 Android 通知栏推送功能 让消息在用户的通知栏上显示&#xff0c;并且点击后跳转到指定的页面 MainActivity.Java import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import andro…...

【LVS】防火墙mark标记解决调度问题

实验环境是在之前部署DR模式集群的基础上做的&#xff0c;参考如下 部署DR模式集群 以http和https为例&#xff0c;当我们在webserver中同时开放80和443端口&#xff0c;那么默认控制是分开轮询的&#xff0c;就会出现了一个轮询错乱的问题&#xff1a; 当第一次访问80被轮询…...

算法笔记|Day20回溯算法II

算法笔记|Day20回溯算法II ☆☆☆☆☆leetcode 39. 组合总和题目分析代码 ☆☆☆☆☆leetcode 40.组合总和II题目分析代码 ☆☆☆☆☆leetcode 131.分割回文串题目分析代码 ☆☆☆☆☆leetcode 39. 组合总和 题目链接&#xff1a;leetcode 39. 组合总和 题目分析 本题采用回…...

Oracle认证1Z0-071线上考试注意事项

目录 一、前言二、回顾过往战绩第一次 裸考&#x1f412;第二次 背题库硬考&#xff01;&#x1f412;第三次 软件卡住&#xff0c;寄&#xff01;&#x1f648;第四次 汇总纠错&#xff0c;通过&#xff01;&#x1f31a; 三、考试流程四、考试注意事项1. 是否需要科学上网2. …...

【C++ 面试 - 基础题】每日 3 题(八)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏&…...

影响LabVIEW工作效率的因素有哪些

影响LabVIEW工作效率的因素可以分为多个方面&#xff0c;涵盖硬件、软件、开发环境和编程习惯等。以下是一些常见的影响因素&#xff1a; 1. 硬件因素 处理器性能&#xff1a;处理器的速度和核心数量对LabVIEW程序的执行效率有很大影响。 内存大小&#xff1a;足够的内存可以保…...

linux 裸机.之SPV5210,dnw,usb,sdk,fastboot刷机(一)

linux 裸机.之SPV5210&#xff0c;dnw&#xff0c;usb&#xff0c;sdk&#xff0c;fastboot刷机&#xff08;一&#xff09;...

性能测试工具LoadRunner

前言&#x1f440;~ 上一章我们介绍了性能测试的一些基本概念&#xff0c;重要的是性能测试的各项指标&#xff0c;今天我们使用性能测试工具LoadRunner简单的完成一次性能测试 性能测试Load Runner LoadRunner是什么&#xff1f; LoadRunner安装 LoadRunner脚本录制 1.录…...

智能归来:深入探索人工智能回归模型的奥秘

人工智能之回归模型 1. 回归模型的数学基础1.1 回归分析的基本原理1.1.1 目标变量与预测变量的关系1.1.2 线性回归模型 1.2 矩阵形式的回归模型1.2.1 回归方程的矩阵表示1.2.2 矩阵运算的基本性质及其在回归分析中的应用 1.3 总结 2. 最小二乘法 (Ordinary Least Squares, OLS)…...

swift 中,对象() 和 对象.init() 的共同点和异同点

在阅读同事的代码时&#xff0c;不同人对对象的初始化方式是不一样的&#xff0c;例如存在一个对象AController, 有些人创建的方式如下&#xff1a; let controller AController()也有人创建的方式如下&#xff1a; let controller AController.init()下面来说明一下&#…...

Google安装JSON-handle扩展

JSON-hande下载地址&#xff1a; JSON-Handle 官网 - 打开json格式文件的浏览编辑器 1. 重命名扩展文件(crx)后缀 为 zip。 2. 解压zip成文件夹&#xff0c;保存到指定目录。 3. Google浏览器地址栏输入 “chrome://extensions/”回车。然后开启 开发者模式。 4. 点击“加载…...

剖析算法内部结构----------贪心算法

什么是贪心算法&#xff1f; 贪心算法&#xff08;Greedy Algorithm&#xff09;是一种在问题求解过程中&#xff0c;每一步都采取当前状态下最优&#xff08;即最有利&#xff09;的选择&#xff0c;从而希望导致最终的全局最优解的算法策略。 贪心算法的核心思想是做选择时&…...

uni-app开发微信小程序注意事项,不要用element-ui

前端扩展组件千万不要用element-ui&#xff0c;开发的时候不报错&#xff0c;发布的时候会报错无法发布。 可以用vant weapp【注意是weapp】 iView weapp 附上hbuilder官方文档 组件的概念 | uni-app官网 (dcloud.net.cn)...

Hibernate的检索策略(lazy、fetch、batch-size)

Hibernate的检索策略包括立即检索和延迟检索&#xff0c;可以在配置文件中通过对lazy、fetch、batch-size属性的设置来进行控制。一对多、多对多、多对一和一对一关系下的不同检索策略将影响对数据库访问的效率。 检索策略 立即检索&#xff0c;立即加载检索方法指定的对象延…...

算法训练(leetcode)第四十六天 | 110. 字符串接龙、105. 有向图的完全可达性、106. 岛屿的周长

刷题记录 *110. 字符串接龙105. 有向图的完全可达性邻接矩阵邻接表 106. 岛屿的周长深搜简化代码 *110. 字符串接龙 题目地址 使用广搜。 本题相当于求最短路径&#xff0c;因此使用广搜。如何应用广搜是一个难点&#xff0c;因为题目给的是字符串而非图的表示&#xff08;邻…...

自定义Mybatis-Plus分布式ID生成器(解决ID长度超过JavaScript整数安全范围问题)

自定义MyBatis-Plus分布式ID生成器&#xff08;解决ID长度超过JavaScript整数安全范围问题&#xff09; 版本 MyBatis-Plus 3.4.1 问题 MyBatis-Plus 默认生成的是 64bit 长整型&#xff0c;而 JS 的 Number 类型精度最高只有 53bit&#xff0c;如果以 Long 类型 ID 和前端…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...