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

【专刷】滑动窗口(一)

📝前言说明:

  • 本专栏主要记录本人的基础算法学习以及LeetCode刷题记录,按专题划分
  • 每题主要记录:(1)本人解法 + 本人屎山代码;(2)优质解法 + 优质代码;(3)精益求精,更好的解法和独特的思想(如果有的话)
  • 文章中的理解仅为个人理解。如有错误,感谢纠错

🎬个人简介:努力学习ing
📋本专栏:C++刷题专栏
📋其他专栏:C语言入门基础,python入门基础,C++学习笔记,Linux
🎀CSDN主页 愚润泽

视频

  • 滑动窗口的关键
  • 209. 长度最小的子数组
    • 个人解
    • 深刻理解滑动窗口
  • 3. 无重复字符的最长子串
    • 个人解
  • 1004. 最大连续1的个数 III
    • 个人解
  • 1658. 将 x 减到 0 的最小操作数
    • 个人解
    • 优质解:


滑动窗口的关键

滑动窗口:同向双指针(即leftright移动方向相同,且right不回退)

滑动窗口是:通过动态调整窗口的左右边界来避免重复计算,从而降低时间复杂度。
其核心思想是维护一个窗口,通过移动右边界扩展窗口、移动左边界收缩窗口,找到满足条件的解。(窗口的状态始终要满足条件)

滑动窗口前提:

  1. 同向双指针
  2. 操作的窗口是连续子数组
  3. 有“单调性”,这种单调是指:可以根据窗口来推出其他的子数组是否满足条件,如:在一个非负数组里面找子数组,如果窗口内的值之和>target,则right往右移动,更大的窗口内的值之和肯定也大于target

代码要点:

  1. leftright标记窗口的左区间和右区间
  2. 进窗口(更新要维护的值)
  3. 判断(新元素进窗口后,维护的值怎么变化),由判断结果决定:出窗口(弄清楚判断满足什么条件的时候,需要出窗口
  4. 更新结果(就题论题,有些是出窗口更新结果,有些是判断的时候更新)

进出窗口是:左右指针的移动

209. 长度最小的子数组

个人解

思路:
本题维护的是子数组内元素的和sum,当sum >= target的时候就可以更新结果,然后出窗口,当不满足条件的时候需要进窗口。

屎山代码:

class Solution {
public:int minSubArrayLen(int target, vector<int>& nums) {int n = nums.size(), ans = n + 1, sum = 0; // sum 是要维护的值for(int left = 0, right = 0; right < n; right++){sum += nums[right]; // 进窗口while(sum >= target) // 判断{ans = min(right - left + 1, ans); // 更新结果sum -= nums[left++]; // 出窗口}}return ans <= n ? ans : 0;}
};

时间复杂度:O(n)
空间复杂度:O(1)


深刻理解滑动窗口

我们通过这道题再剖析一下滑动窗口,这道题为什么能使用滑动窗口,从暴力解法到滑动窗口的优化。

暴力解法
left从左向右遍历数组,right在每个left下,再遍历数组,获得每个子数组的信息。时间复杂度O( n 2 n^2 n2)

如何优化成滑动窗口?

请添加图片描述
滑动窗口的正确性就是:单调性保证的,利用单调性规避了很多没有必要的枚举!


3. 无重复字符的最长子串

个人解

思路:
维护(判断):窗口内的每个字符出现个数不超过 1
因为本题是找最长:所以,满足条件的时候尽可能的进窗口。
而上一题,是找最短,所以当满足条件的时候是出窗口。

用时:5:00
屎山代码:

class Solution {
public:int lengthOfLongestSubstring(string s) {int n = s.size(), ans = 0;map<char, int> cnt;for(int left = 0, right = 0; right < n; right++){cnt[s[right]]++; // 进窗口while(cnt[s[right]] > 1) // 判断{cnt[s[left]]--;left++; // 出窗口}ans = max(ans, right - left + 1); // 更新结果}return ans;}
};

时间复杂度:O(n)
空间复杂度:O(1)


1004. 最大连续1的个数 III

个人解

思路:

  • 维护变量:窗口内的0的个数要<=k
  • 进窗口:进窗口时更新窗口内变量的值(通过判断进入的是不是0)
  • 判断(出窗口操作一般依托于判断):什么时候需要出窗口?当窗口内的数量大于k,所以这就是判断条件
  • 出窗口:随着判断也就顺便完成了。出窗口时也需要更新窗口内维护的变量的值。
  • 更新变量:因为判断的是不满足的条件,所以在出窗口后更新(出窗口后一定满足条件)

用时:6:48
屎山代码:

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

时间复杂度:O(n)
空间复杂度:O(1)


1658. 将 x 减到 0 的最小操作数

个人解

思路:
将题目转换成:求满足元素和==target的最长子数组
先对数组元素求和sum。然后target == sum - x
用时:13:00
屎山代码:

class Solution {
public:int minOperations(vector<int>& nums, int x) {int target = std::accumulate(nums.begin(), nums.end(),0) - x;if(target < 0){return -1;}if(target == 0){return nums.size();}int n = nums.size(), sum = 0, len = 0;for(int left = 0, right = 0; right < n; right++){sum += nums[right]; // 入窗口while(sum >= target) // 判断{if(sum == target){len = max(right - left + 1, len); // 更新结果}sum -= nums[left]; // 出窗口left++;}}return len == 0 ? -1 : n - len; }
};

时间复杂度:O(n)
空间复杂度:O(1)


优质解:

看了一下别人的题解,用滑动窗口的也是这种逆向思维转换一下。


🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!

相关文章:

  • 字符串系列一>二进制求和
  • HTML5+CSS3小实例:CSS立方体
  • 在RK3588上使用哪个流媒体服务器合适
  • 性能比拼: Elixir vs Go(第二轮)
  • JAVA的泛型
  • C++项目 —— 基于多设计模式下的同步异步日志系统(3)(日志器类)
  • 前端面试中高频手撕[待补充]
  • BR_频谱20dB 带宽(RF/TRM/CA/BV-05-C [TX Output Spectrum – 20 dB Bandwidth])
  • RAG工程-基于LangChain 实现 Naive RAG
  • 从GET到POST:HTTP请求的攻防实战与CTF挑战解析
  • 嵌入式linux系统中内存管理的方法与实现
  • 筑基挑战 | 第14期
  • UI文件上传
  • AI与IT的共生
  • 小测验——已经能利用数据集里面的相机外参调整后看到渲染图像
  • 网页聊天系统项目
  • 谷歌新域名结构:Hreflang的未来展望
  • C++ 基于多设计模式下的同步异步⽇志系统-1准备工作
  • 闩锁效应(latch up)
  • bat脚本转换为EXE应用程序文件
  • 南部战区回应菲护卫艇非法侵入中国黄岩岛领海:依法警告驱离
  • 揭晓!人形机器人半马完赛奖+专项奖发布
  • 拒绝“假期刺客”,澎湃启动“五一”消费维权线索征集
  • 北京:义务教育阶段入学将积极为多孩家庭长幼随学创造条件
  • 助力外贸拓内销,上海16家电商平台与近80家外贸企业现场对接
  • 蓝思科技一季度净利增近四成,预计关税对整体经营影响非常有限