算法练习-长度最小的子数组(思路+流程图+代码)

难度参考

        难度:简单

        分类:数组

        难度与分类由我所参与的培训课程提供,但需要注意的是,难度与分类仅供参考。以下内容均为个人笔记,旨在督促自己认真学习。

题目

        给定一个含有个正整数的数组和一个正整数s,找出该数组中满足其和≥s的长度最小的连续子数组,并返回其长度。如果不存在符合条件的子数组,返回0。

        示例1:

        输入:s=7,
                   nums=[2,3,1,2,4,3]
        输出:2
        解释:子数组[4,3]是该条件下的长度最小的子数组。

思路

暴力做法

        使用暴力法解决这道题的思路是遍历所有可能的连续子数组,计算它们的和,并找到满足条件的最小子数组长度。以下是暴力法的详细题解:

  1. 初始化一些变量,包括最小长度 minLength 初始为正无穷大。

  2. 使用两层循环,外层循环以每个元素为起点,内层循环遍历从该起点开始的子数组。外层循环变量 start 从0开始,内层循环变量 endstart 开始。

  3. 在内层循环中,计算子数组的和 sum,即从 nums[start]nums[end] 的元素的累加和。

  4. 如果 sum 大于或等于目标值 s,说明当前子数组的和满足条件,可以记录下当前子数组的长度 end - start + 1

  5. 在外层循环中,不断更新 minLength,即记录当前满足条件的子数组的最小长度。

  6. 继续外层循环,直到遍历完整个数组。

  7. 最后,如果 minLength 没有被更新过,说明没有满足条件的子数组,返回0;否则,返回 minLength

        这个算法的核心思想是遍历所有可能的子数组,计算它们的和并比较长度,找到最小长度的满足条件的子数组。由于使用了两层循环,时间复杂度是O(n^2),其中n是数组的长度。这个算法虽然不如滑动窗口法高效,但是可以解决问题。

        暴力做法不再提供示例与梳理,感觉可以直接看代码。

滑动窗口

        可以使用滑动窗口的方法解决这个问题。滑动窗口是维护一个连续子数组的常用技巧,通过左指针和右指针来移动窗口,根据窗口内元素的和来调整窗口的大小。具体步骤如下:

  1. 初始化左指针 left 为0,右指针 right 为0,以及窗口内元素的和 sum 为0。

  2. 使用右指针 right 向右遍历数组,不断将元素添加到窗口内,并更新 sum

  3. sum 大于等于给定的正整数 s 时,记录当前窗口的长度 right - left + 1

  4. 缩小窗口,即左指针 left 向右移动,同时从 sum 中减去左边界的元素,直到 sum 小于 s

  5. 重复步骤2到4,直到遍历完整个数组。

  6. 在整个过程中,不断更新最小子数组的长度,最终得到最小长度。

通过滑动窗口找到最小长度的连续子数组,时间复杂度为O(n),其中n是数组的长度。

示例

        理解滑动窗口算法可能有点抽象,让我尝试以更简单的方式解释它。

        简单解释:

        滑动窗口算法就像你在一堆连续的数字中寻找一个连续的子集,这个子集的和大于等于给定的值s,而且这个子集的长度要尽可能小。

        首先,你从数组的开头找到一个子集,看它的和是否满足条件。如果和小于s,你就继续扩大子集,添加更多的数字。如果和大于等于s,你记录下这个子集的长度。

        接下来,你缩小子集的范围,从左边开始移除数字,然后再检查新的子集是否满足条件。如果满足,你再次记录子集的长度,然后继续缩小范围。

        你不断地重复这个过程,直到遍历完整个数组。最终,你会找到一个满足条件的子集,它的长度是最小的。

        这就是滑动窗口算法的核心思想:不断调整子集的范围,以找到满足条件的最小子集。

        让我们使用一个示例来说明滑动窗口算法的工作方式:

        示例:

        假设有一个数组 nums,其内容如下:

nums = [2, 3, 1, 2, 4, 3]

        我们的目标是找到一个连续的子数组,该子数组的和大于等于7,并且长度尽可能小。

        步骤1:初始化窗口

        我们从左到右遍历数组,初始化左指针 left 和右指针 right,以及窗口内的和 sum

left = 0, right = 0, sum = 0

        步骤2:扩展窗口

        我们开始扩展窗口,将右指针 right 向右移动,逐个添加元素,并更新 sum 的值。我们的目标是找到一个子数组,其和大于等于7。

left = 0, right = 0, sum = 2 
left = 0, right = 1, sum = 5 
left = 0, right = 2, sum = 6 
left = 0, right = 3, sum = 8

        在这个过程中,当 sum 大于等于7时,我们记录下当前窗口的长度(right - left + 1),并且这是我们找到的目前最小的长度。

        步骤3:缩小窗口

        接下来,我们需要缩小窗口,即将左指针 left 向右移动,同时从 sum 中减去左边界的元素。我们不断缩小窗口,以尝试找到更小的子数组。

left = 1, right = 3, sum = 7

        在这一步,我们找到了一个和为7的子数组,长度为3,这是目前找到的最小长度。

        步骤4:继续寻找

        然后,我们继续向右移动右指针 right,并尝试寻找更小的子数组。

left = 1, right = 4, sum = 11

        在这一步,我们找到了一个和为11的子数组,长度为4。

        步骤5:缩小窗口

        接着,我们再次缩小窗口,继续寻找更小的子数组。

left = 2, right = 4, sum = 9

        在这一步,我们找到了一个和为9的子数组,长度为3。

        步骤6:继续寻找

        我们继续向右移动右指针 right,寻找更小的子数组。

left = 2, right = 5, sum = 12

        在这一步,我们找到了一个和为12的子数组,长度为4。

        步骤7:缩小窗口

        最后,我们再次缩小窗口。

left = 3, right = 5, sum = 10

        在这一步,我们找到了一个和为10的子数组,长度为3。

        图示:      

        2+3+1+2=8>7(找出该数组中满足其和≥s的长度),第一次更新滑动窗口长度。

        尝试缩小窗口(移动左指针),发现3+1+2=6<7。

        因此,继续寻找(移动右指针),调整窗口(1+2+4>7),第二次更新滑动窗口长度。

        同理,在尝试缩小窗口(移动左指针【先】)与继续寻找(移动右指针【后】)之后,调整窗口(1+2+4>7),第三次更新滑动窗口长度。

        尝试缩小窗口(移动左指针),发现4+3>=7,第四次更新滑动窗口长度。

        尝试缩小窗口(移动左指针),发现3<7, 继续寻找(移动右指针), 右指针 j > 数组长度,结束循环。我们就得到了所需要的窗口长度(即该数组中满足其和≥s的长度最小的连续子数组的长度)。

        结果:

        在整个过程中,我们不断调整窗口的大小,以找到和大于等于7的最小子数组。最终,我们找到了一个和为7的子数组,长度为2。这是我们要找的答案。

        所以,滑动窗口算法的结果是2,表示最小连续子数组的长度为2,即子数组 [4, 3]

梳理

        滑动窗口算法之所以能够实现找到满足条件的最小连续子数组,是因为它巧妙地利用了窗口的概念,通过不断调整窗口的大小和位置,来搜索满足条件的最小子数组。以下是为什么这个算法能够实现的原因:

  1. 窗口的左右边界移动: 算法使用两个指针,一个左指针和一个右指针,它们分别表示当前窗口的左边界和右边界。通过不断移动这两个指针,算法模拟了不同窗口的情况。

  2. 窗口内元素和的计算: 算法维护一个变量 sum,用于记录当前窗口内元素的和。随着右指针的移动,不断将新元素添加到窗口内,并更新 sum。这使得算法能够动态地计算窗口内元素的和。

  3. 根据和的大小调整窗口: 在每一步中,算法检查 sum 是否满足给定的条件(例如,是否大于等于s)。如果满足条件,算法会记录当前窗口的长度,然后尝试缩小窗口,即移动左指针。如果不满足条件,算法会继续扩大窗口,即移动右指针。

  4. 不断更新最小长度: 算法在整个过程中不断记录最小的子数组长度。每当找到一个满足条件的子数组时,它会与之前记录的最小长度比较,然后更新最小长度。这确保了算法找到的是最小的满足条件的子数组。

  5. 遍历整个数组: 算法通过不断移动右指针,遍历整个数组,以寻找满足条件的子数组。因为算法考虑了数组中的每个元素,所以它能够找到所有可能的子数组,从中选择最小长度的子数组。

        总结来说,滑动窗口算法通过动态地维护一个窗口,根据窗口内元素和的大小来调整窗口的位置和大小,从而找到满足条件的最小子数组。它的核心思想是不断地搜索可能的子数组,然后选择最小长度的子数组作为答案。这个算法的时间复杂度为O(n),因为每个元素最多被访问两次(一次添加到窗口,一次从窗口移除),其中n是数组的长度。

代码

暴力做法

#include <iostream>
#include <vector>
#include <climits> // 包含 <climits> 头文件以引入 INT_MAXusing namespace std;// 定义一个函数,找到满足和≥s的最短连续子数组的长度(暴力法)
int minSubArrayLen(int s, vector<int>& nums) {int n = nums.size();  // 获取数组的大小int minLength = INT_MAX;  // 初始化最小长度为最大整数for (int start = 0; start < n; start++) {  // 以每个元素为起点int sum = 0;  // 定义当前子数组的和for (int end = start; end < n; end++) {  // 从起点开始遍历子数组sum += nums[end];  // 向子数组内添加元素if (sum >= s) {  // 如果子数组的和满足条件minLength = min(minLength, end - start + 1);  // 更新最小长度break;  // 退出内层循环,继续下一个起点}}}// 如果minLength没有被更新,说明没有满足条件的子数组,返回0;否则返回最小长度return minLength == INT_MAX ? 0 : minLength;
}int main() {int s = 7;  // 给定的正整数svector<int> nums = {2, 3, 1, 2, 4, 3};  // 给定的正整数数组// 调用函数找到满足条件的最短连续子数组的长度(暴力法)int result = minSubArrayLen(s, nums);cout << "最小连续子数组的长度为:" << result << endl;  // 输出结果return 0;
}

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

滑动窗口

#include <iostream>
#include <vector>
#include <climits> // 包含 <climits> 头文件以引入 INT_MAXusing namespace std;// 定义一个函数,找到满足和≥s的最短连续子数组的长度
int minSubArrayLen(int s, vector<int>& nums) {int n = nums.size();  // 获取数组的大小int minLength = INT_MAX;  // 初始化最小长度为最大整数int left = 0;  // 定义左指针int sum = 0;  // 定义当前窗口内元素的和for (int right = 0; right < n; right++) {  // 使用右指针遍历数组sum += nums[right];  // 向窗口内添加一个元素while (sum >= s) {  // 当窗口内元素和大于等于s时minLength = min(minLength, right - left + 1);  // 更新最小长度sum -= nums[left];  // 缩小窗口,左指针向右移动left++;  // 左指针向右移动}}// 如果minLength没有被更新,说明没有满足条件的子数组,返回0;否则返回最小长度return minLength == INT_MAX ? 0 : minLength;
}int main() {int s = 7;  // 给定的正整数svector<int> nums = {2, 3, 1, 2, 4, 3};  // 给定的正整数数组// 调用函数找到满足条件的最短连续子数组的长度int result = minSubArrayLen(s, nums);cout << "最小连续子数组的长度为:" << result << endl;  // 输出结果return 0;
}

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

打卡

        暴力做法打卡

        滑动窗口打卡

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

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

相关文章

redisson的延时队列机制简述

概述 业务中经常会遇到一些延迟执行的需求&#xff1b;通常想到的都是rabbitmq或者rocketmq的延迟消息&#xff1b; 但是系统中不一定集成了mq&#xff0c;但为了控制分布式下的并发&#xff0c;一般redis都是有集成的&#xff1b; redis的key过期监听那个时间不准确&#xff…

在 wsl-ubuntu 里通过 docker 启动 gpu-jupyter

在 wsl-ubuntu 里通过 docker 启动 gpu-jupyter 0. 背景1. 安装 docker-ce2. 安装 NVIDIA Container Toolkit3. 使用 nvidia-ctk 命令配置容器运行4. 通过 docker 运行 nvidia-smi5. 运行 gpu-jupyter6. 访问 gpu-jupyter7. 测试 gpu-jupyter 是否可以访问 cuda 0. 背景 今天突…

Mysql详细安装步骤

Linux 安装 MySQL【超详细版】 ​编辑 我叫BuGu    2023-05-11 16:48:10 发布 一、安装 MySQL 的准备工作 1. 查看系统版本 cat /etc/redhat-release2. 查看系统是否已经安装过 MySQL 查看是否安装了 MySQL rpm -qa | grep mysql查看是否有安装 mariadb,该软件与 MySQ…

qt学习:进度条,水平滑动条,垂直滑动条+rgb调试实战

目录 水平滑动条&#xff0c;垂直滑动条 常用信号 进度条 常用信号 修改进度条 例子 rgb调色 配置ui界面 编写3个进度条的事件函数 添加链表容器和按钮索引 在.h里的类定义 初始化链表容器和按钮索引 编写添加颜色的按钮点击事件函数 效果 水平滑动条&#xff0c…

ChatGPT正确打开方式与GPT-4.5的key最新获取方式

前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff1a;https://www.captainbed.cn/z ChatGPT体验地址 文章目录 前言4.5key价格泄漏ChatGPT4.0使用地址ChatGPT正确打开方式最新功能语音助手存档…

【REMB 】翻译:草案remb-03

REMB REMB消息 以及 绝对时间戳选项 在带宽估计中的使用 :an absolute-value timestamp option for use in bandwidth estimatoin. 接收方带宽估计的RTCP消息 REMB 这位大神翻译的更好。 RTCP message for Receiver Estimated Maximum Bitrate draft-alvestrand-rmcat-remb-03…

.NetCore Flurl.Http 4.0.0 以上管理客户端

参考原文地址&#xff1a;Managing Clients - Flurl 管理客户端 Flurl.Http 构建在堆栈之上System.Net.Http。如果您熟悉HttpClient&#xff0c;那么您可能听说过这个建议&#xff1a;不要为每个请求创建一个新客户端&#xff1b;重复使用它们&#xff0c;否则将面临后…

自动化测试框架有哪些?

前言 自动化测试常用的Python框架有哪些&#xff1f;常用的框架有Robot Framework、Pytest、UnitTest/PyUnit、Behave、Lettuce。Pytest、Robot Framework和UnitTest主要用于功能与单元测试&#xff0c;Lettuce和Behave仅适用于行为驱动测试。 一、Robot Framework Python测…

6.4.2转换文件

6.4.2转换文件 利用Swf2VideoConverter2可以很方便地将Flash动画(*.swf)转换为其它的视频格式。 1&#xff0e;单击“添加”按钮&#xff0c;在弹出的下拉菜单中选择“添加文件”&#xff0c;在弹出的“Open Swf Files(打开Swf文件)”窗口中选择swf文件(如&#xff1a;那些花…

ArcGIS Pro中怎么加载在线地图

当我们在制图的时候&#xff0c;有的时候需要加载在线地图&#xff0c;在ArcGIS Pro中加载在线地图的方式有很多&#xff0c;这里为大家介绍一下加载的方法&#xff0c;希望能对你有所帮助。 加载底图 在菜单栏上选择地图&#xff0c;点击底图&#xff0c;可以看到所有可加载…

网络爬虫采集工具

在当今数字化的时代&#xff0c;获取海量数据对于企业、学术界和个人都至关重要。网络爬虫成为一种强大的工具&#xff0c;能够从互联网上抓取并提取所需的信息。本文将专心分享关于网络爬虫采集数据的全面指南&#xff0c;深入探讨其原理、应用场景以及使用过程中可能遇到的挑…

Docker 安装 MySQ

Docker 安装 MySQL MySQL 是世界上最受欢迎的开源数据库。凭借其可靠性、易用性和性能&#xff0c;MySQL 已成为 Web 应用程序的数据库优先选择。 1、查看可用的 MySQL 版本 访问 MySQL 镜像库地址&#xff1a;https://hub.docker.com/_/mysql?tabtags 。 可以通过 Sort b…