[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一直 维护这个区间的和,然后这两个指针从左向右移动的过程非常像一个窗口在这个数组里滑来滑去。

什么时候用滑动窗口?

利用单调性,用滑动窗口解决问题。

当我们发现在暴力求解时,两个指针都可以做到 不回退,都是向同一个方向移动的时候,此时就可以用滑动窗口。

滑动窗口怎么用?

  1. 初始left=0,right=0,充当窗口左端点,右端点。用left,right标记窗口左区间,右区间。
  2. 右窗口(++right)(右值进窗口)
  3. 判断
    • 根据判断决定是否 左窗口(++left)(左值出窗口)
  1. 更新结果
    • 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不回退一直往前走

解法二:利用规律,使用 “滑动窗口” 解决问题

  1. left=0,right=0
  2. 进窗口
  3. 判断
    • 出窗口
  1. 更新结果

进窗口、判断、出窗口,更新结果是一个大循环过程。直到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,假设最多可以翻转 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。

题解

题目说的翻转实际上是把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是同向移动的,利用这个规律,使用滑动窗口解决问题

解法二:利用规律,使用滑动窗口

  1. left=0,right=0
  2. 进窗口
  3. 判断
    • 出窗口
  1. 更新结果

进窗口 -> 如果是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

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

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

相关文章

安卓binder驱动内核日志调试打印开放及原理(第一节)

背景&#xff1a; 经常有学员朋友在做系统开发时候&#xff0c;有时候遇到binder相关的一些问题&#xff0c;这个时候可能就需要比较多的binder相关日志&#xff0c;但是正常情况下这些binder通讯的的内核日志都是没有的打印的&#xff0c;因为经常binder通讯太过于频繁&#…

docker 安装达梦数据库(离线)

docker安装达梦数据库&#xff0c;官网上已经下载不了docker版本的了&#xff0c;下面可通过百度网盘下载 通过网盘分享的文件&#xff1a;dm8_20240715_x86_rh6_rq_single.tar.zip 链接: https://pan.baidu.com/s/1_ejcs_bRLZpICf69mPdK2w?pwdszj9 提取码: szj9 上传到服务…

MWC 2025 | 紫光展锐联合移远通信推出全面支持R16特性的5G模组RG620UA-EU

2025年世界移动通信大会&#xff08;MWC 2025&#xff09;期间&#xff0c;紫光展锐联合移远通信&#xff0c;正式发布了全面支持5G R16特性的模组RG620UA-EU&#xff0c;以强大的灵活性和便捷性赋能产业。 展锐芯加持&#xff0c;关键性能优异 RG620UA-EU模组基于紫光展锐V62…

达梦适配记录-检查服务器

service DmServicedmdb status 查看是否开启&#xff0c;没有配置systemctl&#xff0c;查看《DM8_Linux 服务脚本使用手册》2.1.2.2 1 &#xff0e;拷贝服务模板文件&#xff08; DmService &#xff09;到目录&#xff08; /opt/dmdbms/bin &#xff09;&#xff0c;并将新文…

Pipeline模式详解:提升程序处理效率的设计模式

文章目录 Pipeline模式详解&#xff1a;提升程序处理效率的设计模式引言Pipeline的基本概念Pipeline的工作原理Pipeline的优势Pipeline的应用场景1. 数据处理2. DevOps中的CI/CD3. 机器学习4. 图像处理 常见的Pipeline实现方式1. 函数式编程中的Pipeline2. 基于消息队列的Pipel…

STM32单片机芯片与内部115 DSP-FIR IIR低通 高通 带通 带阻 中值 自适应 滤波器 逐个数据实时 样条插值拟合

目录 一、FIR 低通、高通、带通、带阻 1、FIR滤波器特点 2、滤波器结构 3、滤波器系数 4、滤波实现 5、FIR 滤波后的群延迟 二、IIR 低通、高通、带通、带阻 1、IIR滤波器特点 2、滤波器结构 3、滤波器系数 4、滤波实现 5、IIR滤波后的群延迟 三、中值滤波 1、中值…

C语言_图书管理系统_借阅系统管理

✨✨ 欢迎大家来到小伞的大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;数据结构与算法 小伞的主页&#xff1a;xiaosan_blog 本文所需对顺序表的理解&#xff1a; 注&#xff1a;由于顺序表实现图书…

表达式基础

文章目录 1、表达式组成1、运算符 2、表达式的分类1、算数运算符1、自增运算符和自减运算2、取余运算(%)3、除法运算(/)4、案例 2、关系运算符3、逻辑运算符4、条件运算符(三目运算符)1、案例 5、赋值运算()1、赋值类型转换2、复合赋值运算 6、逗号运算7、取地址运算(&)8、…

除了合并接口,还有哪些优化 Flask API 的方法?

除了合并接口&#xff0c;还有许多其他方法可以优化 Flask API&#xff0c;以下从性能优化、代码结构优化、安全性优化、错误处理优化等方面详细介绍&#xff1a; 性能优化 1. 使用缓存 内存缓存&#xff1a;可以使用 Flask-Caching 扩展来实现内存缓存&#xff0c;减少对数…

Web服务器配置

配置虚拟主机 通过虚拟主机&#xff0c;可以实现用自定义的域名来访问&#xff0c;并且可以为不同的域名指定不同的站点目录。 配置IP地址和域名的映射关系 申请真实的域名需要一定的费用&#xff0c;为了方便开发&#xff0c;可以通过修改hosts文件来实现将任意域名解析到本…

爬虫逆向实战小记——解决webpack实记

注意&#xff01;&#xff01;&#xff01;&#xff01;某XX网站实例仅作为学习案例&#xff0c;禁止其他个人以及团体做谋利用途&#xff01;&#xff01;&#xff01; aHR0cHM6Ly9wbW9zLnhqLnNnY2MuY29tLmNuOjIwMDgwL3B4Zi1zZXR0bGVtZW50LW91dG5ldHB1Yi8jL3B4Zi1zZXR0bGVtZW5…

蓝桥杯 之 前缀和与查分

文章目录 题目求和棋盘挖矿 前缀和有利于快速求解 区间的和、异或值 、乘积等情况差分是前缀和的反操作 前缀和 一维前缀和&#xff1a; # 原始的数组num,下标从1到n n len(num) pre [0]*(n1) for i in range(n):pre[i1] pre[i] num[i] # 如果需要求解num[l] 到num[r] 的区…

Windows10下本地搭建Manim环境

文章目录 1. 简介2. Python环境3. uv工具4. Latex软件5. 安装Manim数学库6. 中文支持参考 1. 简介 manim是个一科普动画的库&#xff0c; 本文用到的是社区版本。 2. Python环境 这个不用多说&#xff0c;可以参考其他的文章。记得把pip也安上。 3. uv工具 上面的pip是老…

#UVM# 关于field automation机制中的 pack_bytes 和unpack_bytes 函数剖析

一 pack_bytes 函数 在 UVM 中,pack_bytes 函数用于将类中的所有字段打包成一个字节流(byte stream)。这是 UVM 提供的字段自动化(field automation)机制的一部分,用于简化数据打包和传输。 extern function int pack_bytes(ref byte unsigned bytestream[], input uv…

YOLOv8 自定义目标检测

一、引言 YOLOv8 不仅支持预训练模型的推理&#xff0c;还允许用户将其应用于自定义对象检测。本文将详细介绍如何使用 YOLOv8 训练一个新的模型&#xff0c;并在自定义数据集上进行对象检测。 二、数据集准备 1. 数据集格式 YOLOv8 支持多种数据集格式&#xff0c;包括 CO…

关于tresos Studio(EB)的MCAL配置之GPT

概念 GPT&#xff0c;全称General Purpose Timer&#xff0c;就是个通用定时器&#xff0c;取的名字奇怪了点。定时器是一定要的&#xff0c;要么提供给BSW去使用&#xff0c;要么提供给OS去使用。 配置 General GptDeinitApi控制接口Gpt_DeInit是否启用 GptEnableDisable…

Dify 开源大语言模型应用开发平台使用(一)

文章目录 一、创建锂电池专业知识解答应用1.1 应用初始化 二、核心功能模块详解2.1 知识库构建2.2 工作流与节点编排节点类型说明工作流设计示例&#xff1a;锂电池选型咨询 2.3 变量管理 三、测试与调试3.1 单元测试3.2 压力测试3.3 安全验证 四、部署与优化建议4.1 部署配置4…

《Java基础 聊天窗口案例:剖析 GUI、文件 I/O 等关键技术知识》

1. 面向对象编程 类与对象&#xff1a;代码中定义了 Chat 类&#xff0c;它是整个程序的核心&#xff0c;封装了与聊天窗口相关的属性和方法。在 main 方法中创建了 Chat 类的对象&#xff0c;并调用其方法来完成相应的功能。继承与多态&#xff1a;ButtonClickListener 类实现…

IDE集成开发环境MyEclipse中安装SVN

打开Myeclipse的help菜单----install from site 点击add弹出对话框 在输入框中输入对应内容 http://subclipse.tigris.org/update_1.10.x 点击OK之后&#xff0c;会刷新出两个选项&#xff0c;需要选中的 点击next&#xff0c;出现许可的时候选中同意&#xff0c;一直结束等…

归并排序:分治哲学的完美演绎与时空平衡的艺术

引言&#xff1a;跨越世纪的算法明珠 在计算机科学的璀璨星河中&#xff0c;归并排序犹如一颗恒久闪耀的明星。1945年&#xff0c;现代计算机之父冯诺伊曼在EDVAC计算机的研发过程中首次系统性地提出了这一算法&#xff0c;其精妙的分治思想不仅奠定了现代排序算法的理论基础&…