[Lc(2)滑动窗口_1] 长度最小的数组 | 无重复字符的最长子串 | 最大连续1的个数 III | 将 x 减到 0 的最小操作数
目录
1. 长度最小的字数组
题解
代码
⭕2.无重复字符的最长子串
题解
代码
3.最大连续1的个数 III
题解
代码
4.将 x 减到 0 的最小操作数
题解
代码

1. 长度最小的字数组
题目链接:209.长度最小的字数组
题目分析:
给定一个含有 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
题解
- 注意题目说的是 正整数 数组,说明数组里面的数是大于等于0的数。
- 因此这道题我们有一种优化的方法。
- 题目让找连续的子数组和>=target,并且长度最小。有很多种情况,但是我们选择的是 最小长度。

算法原理:
不管什么题,首先我们一定会先想到的是 暴力求解,因为只有暴力求解出来了,我们就可以在暴力求解的基础上进行优化~
解法一:暴力枚举出所有的子数组的和
两层for循环,O(N^2)
for(int i=0;i<n;i++)for(int j=i;j<n;j++)sum+=num[j];
//固定一个数,挨个往后加if(sum>=target)min(len,j-i+1)
注意到此时暴力枚举是有优化的。
题目说的是一个 正整数数组,都是大于等于0的数,这个 sum是呈现出递增的状态的,单调递增!
在暴力求解中,此时right还要++,但是注意题目本来要求的就是 最小长度
此时sum在加上往上走了一步的right的num[right],一定是满足sum>=target,但是len变成5了,一定不会是最终结果
因此当条件已经满足sum>=target ,right就不用动了。right后面也就不用再枚举了。

那现在让 left+1,right和left指向同一下标,然后再重复上面过程,那有个问题,这段区间的和能不能直接算出来?
- 当然可以。
- 现在sum=8,我只需要把让sum减去num[left],不就是现在left和right所在的区间和算出来吗。
- 没有必要让right傻傻的回退然后重新加。因此right不动,更新sum=6.

因此我们从暴力枚举中发现两个优化:
- 一个是right 满足后,后面不用枚举
- 一个left++,right不用回退,
所以我们可以利用单调性,使用双指针优化。
解法二:利用单调性,使用 “同向双指针” 来优化
当我们在暴力枚举的策略中发现left和right都是从左向右一个方向移动,我们就称为这两个指针叫做同向指针。同向双指针又称为滑动窗口。
什么是滑动窗口?
本质上是 “同向双指针”,left从左到右移动,right不回退,从左到右移动,用left和right一直 维护这个区间的和,然后这两个指针从左向右移动的过程非常像一个窗口在这个数组里滑来滑去。

什么时候用滑动窗口?
利用单调性,用滑动窗口解决问题。
当我们发现在暴力求解时,两个指针都可以做到 不回退,都是向同一个方向移动的时候,此时就可以用滑动窗口。
滑动窗口怎么用?
- 初始left=0,right=0,充当窗口左端点,右端点。用left,right标记窗口左区间,右区间。
- 右窗口(++right)(右值进窗口)
- 判断
-
- 根据判断决定是否 左窗口(++left)(左值出窗口)
- 更新结果
-
- 2,3都有可能会更新结果,看题目要求
左窗口,判断,右窗口一直循环,直到right 超过区间长度结束,更新结果看题目要求(右窗口,左窗口都有可能),。

滑动窗口正确性
- 暴力枚举肯定对的,因为已经把所有子数组的情况都找出来了。
- 虽然滑动窗口并没有把没有把所有情况都枚举出来,但是这里利用单调性,规避了没有必要的枚举
- 虽然没有把所有情况真正枚举出来,但是已经判断出有些子数组不是最终结果,已经把所有结果都考虑进来了,所以这种策略是跟暴力枚举是一样正确的。
滑动窗口时间复杂度
进窗口是一个循环,判断也是一个循环。
两层循环套在一起。可能会觉得时间复杂度O(N^2),但是不能看代码算时间复杂度,要看实际情况分析实际复杂度。
实际我们只会让right向前移动,left也向前移动,即使时最坏情况,right移动到最后一个元素,left 也移动到最后一个元素,因为单调性,总共也就操作了 n+n=2n 次 整体时间复杂度O(N)。

代码

要考虑到,栈溢出(heap-buffer-overflow) 的边界情况

可详见前文
在Leetcode中,无穷大和无穷小分别怎么表示
C/C++中可以使用INT_MAX和INT_MIN
⭕2.无重复字符的最长子串
题目链接:3. 无重复字符的最长子串
题目分析:
给定一个字符串 s ,请你找出其中不含有重复字符的 最长 子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
子串和子数组都是连续的
❗❗❗ 模拟分析示例:

题解
算法原理:
首先还是暴力枚举,然后根据暴力枚举进行优化。
- 以下面为例,两层for循环,但是下面找到的结果都是我们站在上帝角度,编译器并不知到什么时候结束。
- 一般对应判断是否有重复元素,我们都可以用哈希表来解决问题。
- 使用哈希表,判断是否有重复元素,比如让你判断一个数组是否有重复,或者两个数组是否有重复都可以用哈希映射!

解法一:暴力枚举+哈希表(判断字符是否重复出现)
O(N^2)
根据解法一做优化,定义一个left,right指针。当right走到有重复的元素后,已经找到一个字串,其中left到right区间每个元素都已经进入hash表。

此时left向前走一步,但是这个区间还是有重复元素,因此left要走到没有重复的区间才行,

然后这个时候以前做法是right回退然后重新往下走,但是这里left到right区间元素本来就在hash表里
因此就不需要right回退了,而是向right继续向前走。然后重复上面过程,直到right走到结尾。结束~

这不就是滑动窗口的思想吗。双向指针,left往前走,right不回退一直往前走
解法二:利用规律,使用 “滑动窗口” 解决问题
- left=0,right=0
- 进窗口
- 判断
-
- 出窗口
- 更新结果
进窗口、判断、出窗口,更新结果是一个大循环过程。直到right到结尾循环结束。
其中判断、出窗口是一个小循环(直到跳出重复字符)。不过时间复杂度还是O(N).
注意:
- 更新结果可能在 进窗口后,判断后,出窗口后,判断后任意一个地方,看题目要求
本题:
- 进窗口 ->-> 让字符进入哈希表
- 判断-> 窗口内出现重复元素
- 出窗口-> 从哈希表中删除该字符
代码
class Solution {
public:int lengthOfLongestSubstring(string s) {//!!if(s.empty()) return 0; // 处理空输入vector<char> str;for(char c:s) str.push_back(c);int left=0,right=0,n=str.size(),len=0;//unordered_set ret;unordered_set<char> ret;while(right<n){
//先检查while(ret.count(str[right])){ret.erase(str[left]);left++;//利用了连续性//表中 发现了右元素已存在//要在左边 进行跳过}
//不存在 就插入ret.insert(str[right]);len=max(len,right-left+1);right++;}return len;}
};
总结一下:
利用单调性,使用 双指针 解决问题。
- 一般left和right,一个指向数组最左边,一个指向数组最右边,然后一次可以排除一批,再然后left++,–right,两个指针是对撞的。
这里利用单调性或者利用规律,使用 滑动窗口 解决问题
- 滑动窗口也使用双指针解决问题,不过left一直从前往后走,right不回退从前往后走,两个指针是同向的。因此滑动窗口本质其实是 同向双指针。
3.最大连续1的个数 III
题目链接:1004. 最大连续1的个数 III
题目分析:
给定一个二进制数组 nums 和一个整数 k,假设最多可以翻转 k 个 0 ,则返回执行操作后 数组中连续 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。
题解
题目说的翻转实际上是把0变成1的意思,最多翻转K次,说明小于等于K都是可以的。

拿到题我们开始肯定想的是暴力求解。
如果直接暴力求解,遇到0->1了,那下一次在遍历就有问题了。
因此我们换一个思路。这道题不是让转化后最大连续1的个数吗。
我们转化为:找出最长的子数组,数组里0的个数不超过K个,这个数组里面0一定能够转化成1。
算法原理:
解法一:暴力枚举+zero计数器
伪代码,两层for循环,统计zero的个数,满足zero>k,统计此时数组长度,然后重新进入循环,注意每次zero都清0
for(int i=0;i<n;++i)for(int j=i;j<n;++j)//双指针 查找出一段区间if(nums[j]==0)++zero;if(zero>k)ret=max(ret,right-left+1)
然后我们根据暴力枚举,看看有没有优化的可能。
定义两个指针left,right,right走到zero>k的位置,zero=3,大于k。

按照暴力求解left++,然后right回溯然后重新往后走。但是我们发现没有必要,现在left往前走一步,你会发现,right还是停留在老位置,这个区间不用在管的,直接丢弃。

因此,让left一直走到zero<=k的位置。然后 right也根本不用回溯 然后在重新走,而是直接往后走就行了。

根据上面的发现,当在暴力枚举中,发现left,right是同向移动的,利用这个规律,使用滑动窗口解决问题
解法二:利用规律,使用滑动窗口
- left=0,right=0
- 进窗口
- 判断
-
- 出窗口
- 更新结果
进窗口 -> 如果是1,不理会。如果是0,计数器+1
判断 -> zero>k
出窗口 -> 如果是1,不理会。如果是0,计数器-1
更新结果:在判断之后在更新
代码
class Solution {
public:int longestOnes(vector<int>& nums, int k) {int left = 0, right = 0, zero = 0;int n = nums.size(), len = 0;while (right < n) {//进 窗口if (nums[right] == 0)zero++;while (zero > k) {//循环判断if (nums[left] == 0)zero--;left++;}len = max(len, right - left + 1);right++;}return len;}
};
4.将 x 减到 0 的最小操作数
题目链接:1658. 将 x 减到 0 的最小操作数
题目分析:
给你一个整数数组 nums 和一个整数 x 。每一次操作时,你应当移除数组 nums 最左边或最右边的元素,然后从 x 中减去该元素的值。请注意,需要 修改 数组以供接下来的操作使用。
如果可以将 x 恰好 减到 0 ,返回 最小操作数 ;否则,返回 -1 。
示例 1:
输入:nums = [1,1,4,2,3], x = 5
输出:2
解释:最佳解决方案是移除后两个元素,将 x 减到 0 。
示例 2:
输入:nums = [5,6,7,8,9], x = 4
输出:-1
示例 3:
输入:nums = [3,2,20,1,1,3], x = 10
输出:5
解释:最佳解决方案是移除后三个元素和前两个元素(总共 5 次操作),将 x 减到 0 。
题解
这道题让每次从数组左右两边移除一个数,然后就是一个新的数组,然后再从新的数组再从左右两边移除一个数。
- 但是如果真的硬着头皮开始做,其实是很困难的。
- 并不知道每次是从最左边走还是最右边找。有可能这次左边下次右边或者还是左边,情况太复杂了。

因此我们可以利用 正难则反 的思想
- 正对面解题太难,那就想对立面,换个思路。
- 不是每次从左右两端找一个数吗,那可能找到情况就是a+b=x,a、b什么情况都要,但是中间这个连续区间的和不也是确定的吗sum-x
- 也就是这道题我们转换成,找出最长的子数组长度,所有元素的和正好等于sum-x,然后数组总长减去这段子区间长度不就是问题答案吗
- 如果没找到说明这个数组不存在将x减到0的数,直接返回-1

解法一:暴力求解
初始left,right指向同一下标,当right走到和大于target的时候,left往前走
按照暴力求解,right要回到和left相同下标,然后right在重新往前走,直到再次走到和大于target的地方停下来,然后重复上面过程。

- 但是今天这里不需要right回溯,因为right回溯后重新走到下面的位置,因为left已经往前走了,这段区间的和肯定是更小了
- 因此就不需要right回溯了。要么right不动,要么right往后走。
- 同向双指针 ----> 本质就是滑动窗口
解法二:使用滑动窗口
代码
class Solution {
public:
int minOperations(vector<int>& nums, int x)
{if(nums.empty()) return -1;int sum=0;for(auto c:nums)sum+=c;// 新增边界条件处理if (sum == x) return nums.size(); // 整个数组和正好等于xif (sum < x) return -1; // 总和不足,无法达成目标int target=sum-x,len=0;int left=0,right=0,n=nums.size(),add=0;while(right<n){add+=nums[right];while(add>target){add-=nums[left];left++;}if(add==target)len=max(len,right-left+1);right++;}//!!!len>0 return (len > 0) ? (nums.size() - len) : -1;
}
};
测试样例跑不全时,要注意对 边界情况 的处理

- 若不存在这样的子数组(
len = 0)
相关文章:
[Lc(2)滑动窗口_1] 长度最小的数组 | 无重复字符的最长子串 | 最大连续1的个数 III | 将 x 减到 0 的最小操作数
目录 1. 长度最小的字数组 题解 代码 ⭕2.无重复字符的最长子串 题解 代码 3.最大连续1的个数 III 题解 代码 4.将 x 减到 0 的最小操作数 题解 代码 1. 长度最小的字数组 题目链接:209.长度最小的字数组 题目分析: 给定一个含有 n 个 正整数 的数组…...
互联网时代如何保证数字足迹的安全,以防个人信息泄露?
用户在网络上所做的几乎所有事情,包括浏览、社交媒体活动、搜索查询、在线订阅,甚至购物,都会留下一条数据线索,这些数据可用于创建用户在线身份的详细档案。如果这些信息暴露,恶意行为者可能会利用它们将用户置于各种…...
海康摄像头接入流媒体服务器实现https域名代理播放
环境 操作系统:Ubuntu 22.04流媒体服务器:srs 官网安装教程srs开启GB28181协议 官网开启教程进行海康摄像头的配置 官网配置教程srs使用systemctl实现开机自启 官网配置教程 nginx配置说明 server {listen 80;server_name a.com;return 301 https://$…...
【C++设计模式】第五篇:原型模式(Prototype)
注意:复现代码时,确保 VS2022 使用 C17/20 标准以支持现代特性。 克隆对象的效率革命 1. 模式定义与用途 核心思想 原型模式:通过复制现有对象(原型)来创建新对象,而非通过new构造。关键用…...
51单片机课综合项目
1、按键控制蜂鸣器实验 1、实验现象:下载程序后,按下K1键蜂鸣器发声一次,按下K2键,蜂鸣器连续发声,再次按下K2键,发声取消 2、使用到的外设模块:蜂鸣器模块beep 独立按键模块 key 3、编程框架(…...
【最大半连通子图——tarjan求最大连通分量,拓扑排序,树形DP】
题目 分析 最大连通分量肯定是满足半连通分量的要求,因此tarjan。 同时为了简化图,我们进行缩点,图一定变为拓扑图。 我们很容易看出,只要是一条不分叉的链,是满足条件的。 于是我们按照拓扑序不断树形DP 建边注意…...
一周学会Flask3 Python Web开发-在模板中渲染WTForms表单视图函数里获取表单数据
锋哥原创的Flask3 Python Web开发 Flask3视频教程: 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 为了能够在模板中渲染表单,我们需要把表单类实例传入模板。首先在视图函数里实例化表单类LoginForm,然…...
DeepSeek R1助力,腾讯AI代码助手解锁音乐创作新
目录 1. DeepSeekR1模型简介2. 歌词创作流程2.1 准备工作2.2 歌词生成技巧 3. 音乐制作环节3.1 主流AI音乐生成平台 4. 歌曲欣赏5. 总结展望 1. DeepSeekR1模型简介 腾讯AI代码助手最新推出的DeepSeekR1模型不仅在代码生成方面表现出色,其强大的自然语言处理能力也…...
用户空间与内核空间切换机制详解
用户空间与内核空间切换机制详解 一、切换触发条件 用户态与内核态的切换由以下三类事件触发: 系统调用 用户程序主动通过int 0x80(x86)或ecall(RISC-V)等指令发起系统调用,请求内核服务(如文件读写、进程创建等)。此时CPU自动进入内核态处理请求,完成后返回用户…...
【微信小程序】每日心情笔记
个人团队的比赛项目,仅供学习交流使用 一、项目基本介绍 1. 项目简介 一款基于微信小程序的轻量化笔记工具,旨在帮助用户通过记录每日心情和事件,更好地管理情绪和生活。用户可以根据日期和心情分类(如开心、平静、难过等&#…...
为AI聊天工具添加一个知识系统 之135 详细设计之76 通用编程语言 之6
本文要点 要点 通用编程语言设计 本设计通过三级符号系统的动态映射与静态验证的有机结合,实现了从文化表达到硬件优化的全链路支持。每个设计决策均可在[用户原始讨论]中找到对应依据,包括: 三级冒号语法 → 提升文化符号可读性圣灵三角…...
前端基础之组件
组件:实现应用中局部功能代码和资源的集合 非单文件组件 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"…...
spring boot整合flyway实现数据的动态维护
1、简单介绍一下flyway Flyway 是一款开源的数据库版本控制工具,主要用于管理数据库结构的变更(如创建表、修改字段、插入数据等)。它通过跟踪和执行版本化的迁移脚本,帮助团队实现数据库变更的自动化。接下来简单介绍一下flyway…...
通往 AI 之路:Python 机器学习入门-线性代数
2.1 线性代数(机器学习的核心) 线性代数是机器学习的基础之一,许多核心算法都依赖矩阵运算。本章将介绍线性代数中的基本概念,包括标量、向量、矩阵、矩阵运算、特征值与特征向量,以及奇异值分解(SVD&…...
Matlab中的均值函数mean
今天调了一个代码里的bug,根源居然是mean函数的使用细节没留意到~ 具体来说,写一个类似k均值聚类那样的程序,交替迭代,其中有一部是使用mean求一堆向量的均值,这些向量存在一个矩阵里,每行对应一个向量。若…...
数据结构知识学习小结
一、动态内存分配基本步骤 1、内存分配简单示例: 个人对于示例的理解: 定义一个整型的指针变量p(着重认为它是一个“变量”我觉得可能会更好理解),这个变量用来存地址的,而不是“值”,malloc函…...
高精算法的用法及其优势
高精度问题是指当数据的位数非常大(超出标准数据类型的范围)时,如何进行计算和存储的问题。常见场景包括大整数的加、减、乘、除、取模等操作。以下是解决高精度问题的常用方法与技巧: 一、数据存储 数组存储 用整型数组存储&am…...
【Spring AOP】_切点类的切点表达式
目录 1. 根据方法签名匹配编写切点表达式 1.1 具体语法 1.2 通配符表达规范 2. 根据注解匹配编写切点表达式 2.1 实现步骤 2.2 元注解及其常用取值含义 2.3 使用自定义注解 2.3.1 编写自定义注解MyAspect 2.3.2 编写切面类MyAspectDemo 2.3.3 编写测试类及测试方法 在…...
多线程-定时任务线程池源码
定时任务线程池 ScheduledThreadPoolExecutor,可以执行定时任务的线程池。这里学习它的基本原理。 定时任务线程池,和普通线程池不同的地方在于,它使用一个延迟队列,延迟队列使用最小堆作为它的数据结构,它会按照任务…...
初次使用 IDE 搭配 Lombok 注解的配置
前言 在 Java 开发的漫漫征程中,我们总会遇到各种提升效率的工具。Lombok 便是其中一款能让代码编写变得更加简洁高效的神奇库。它通过注解的方式,巧妙地在编译阶段为我们生成那些繁琐的样板代码,比如 getter、setter、构造函数等。然而&…...
云服数据存储接口:CloudSever
云服数据存储接口:CloudSever 迷你世界 更新时间: 2024-04-28 19:09:10 具体函数名及描述如下: 序号 函数名 函数描述 1 setOrderDataBykey(...) 设置排行榜中指定键的数值 2 removeOrderDataByKey(...) 删除排行榜中指定键的数值 …...
关于 QPalette设置按钮背景未显示出来 的解决方法
若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/146047054 长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV…...
上传文件到对象存储是选择前端还是后端
对于云上对象存储的上传方式选择(前端直传或后端代理上传),需综合考虑安全性、性能、成本、业务需求等因素。 1. 推荐前端直传的场景 适用条件: 大文件上传(如视频、大型数据集)高并发场景(如…...
mysql下载与安装
一、mysql下载: MySQL获取: 官网:www.mysql.com 也可以从Oracle官方进入:https://www.oracle.com/ 下载地址:https://downloads.mysql.com/archives/community/ 选择对应的版本和对应的操作系统ÿ…...
Python练习(握手问题,进制转换,日期问题,位运算,求和)
一. 握手问题 代码实现 ans0for i in range(1,51):for j in range(i1,51):if i<7 and j<7:continueelse:ans 1print(ans) 这道题可以看成是50个人都握了手减去7个人没握手的次数 答案:1204 二.将十进制整数拆解 2.1门牌制作 代码实现 ans0for i in ra…...
小程序分类页面
1创建cate分支 2.cate滑动界面布局 获取滑动界面高度 3.获取并渲染一级分类的列表数据 4.渲染二级和三级分类列表 获取二级列表的数据 5.渲染二级分类列表的UI结构 6.动态渲染三级分类列表...
HTML + CSS 题目
1.说说你对盒子模型的理解? 一、是什么 对一个文档进行布局的时候,浏览器渲染引擎会根据标准之一的css基础盒模型,将所有元素表示为一个个矩形的盒子。 一个盒子由四个部分组成: content,padding,border,margin 下…...
计算机视觉|ViT详解:打破视觉与语言界限
一、ViT 的诞生背景 在计算机视觉领域的发展中,卷积神经网络(CNN)一直占据重要地位。自 2012 年 AlexNet 在 ImageNet 大赛中取得优异成绩后,CNN 在图像分类任务中显示出强大能力。随后,VGG、ResNet 等深度网络架构不…...
Node JS 调用模型Xenova_all-MiniLM-L6-v2实战
本篇通过将句子数组转换为句子的向量表示,并通过平均池化和归一化处理,生成适合机器学习或深度学习任务使用的特征向量为例,演示通过NodeJS 的方式调用Xenova/all-MiniLM-L6-v2 的过程。 关于 all-MiniLM-L6-v2 的介绍,可以参照上…...
React + TypeScript 实战指南:用类型守护你的组件
TypeScript 为 React 开发带来了强大的类型安全保障,这里解析常见的一些TS写法: 一、组件基础类型 1. 函数组件定义 // 显式声明 Props 类型并标注返回值 interface WelcomeProps {name: string;age?: number; // 可选属性 }const Welcome: React.FC…...
