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

这篇具有很好参考价值的文章主要介绍了算法练习-长度最小的子数组(思路+流程图+代码)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

难度参考

        难度:简单

        分类:数组

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

题目

        给定一个含有个正整数的数组和一个正整数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_MAX

using 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;  // 给定的正整数s
    vector<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_MAX

using 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;  // 给定的正整数s
    vector<int> nums = {2, 3, 1, 2, 4, 3};  // 给定的正整数数组

    // 调用函数找到满足条件的最短连续子数组的长度
    int result = minSubArrayLen(s, nums);

    cout << "最小连续子数组的长度为:" << result << endl;  // 输出结果

    return 0;
}

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

打卡

        暴力做法打卡

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

        滑动窗口打卡

算法练习-长度最小的子数组(思路+流程图+代码),算法编程笔记,流程图文章来源地址https://www.toymoban.com/news/detail-800921.html

到了这里,关于算法练习-长度最小的子数组(思路+流程图+代码)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 算法练习-替换数字(思路+流程图+代码)

            难度:简单         分类:字符串         难度与分类由我所参与的培训课程提供,但需要注意的是,难度与分类仅供参考。以下内容均为个人笔记,旨在督促自己认真学习。         给定一个字符串S,它包含小写字母和数字字符,请编写一个函数,将字符串

    2024年02月20日
    浏览(48)
  • 算法练习-赎金信(思路+流程图+代码)

            难度:中等         分类:哈希表         难度与分类由我所参与的培训课程提供,但需要注意的是,难度与分类仅供参考。且所在课程未提供测试平台,故实现代码主要为自行测试的那种,以下内容均为个人笔记,旨在督促自己认真学习。         给你

    2024年02月22日
    浏览(47)
  • java数据结构与算法刷题-----LeetCode209. 长度最小的子数组

    java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完): https://blog.csdn.net/grd_java/article/details/123063846 解题思路 代码:时间复杂度O(n).空间复杂度O(1)

    2024年01月21日
    浏览(54)
  • 算法训练 Day 2 | 数组:977.有序数组的平方,209.长度最小的子数组,59.螺旋矩阵II

    977. 有序数组的平方 第一想法:暴力破解 看完题解想法:朝着双指针方向想 遇到困难: 用双指针的话,一开始想到两边指针往中间靠,逐个将最大值赋给结果数组。和题解不同的是,循环条件我写了  while (left != right) {...} ,相比于题解的  while (left = right) {...} ,我需要在后

    2023年04月12日
    浏览(47)
  • 算法刷题营【Day2】:: 双指针算法应用:滑动窗口 :209. 长度最小的子数组

    本内容是笔者结合《代码随想录》总结所得,记录学习过程,分享知识! 目录: 1. 开篇例题:209. 长度最小的子数组 2. 题解参考 - - 2.1 方法一:暴力法 - - 2.2 方法二:滑动窗口 3. 方法思路点拨:滑动窗口 - - 3.1 直白解释 - - 3.2 本题思路点拨 4. 相关题集 1. 开篇例题:209. 长度

    2024年02月04日
    浏览(47)
  • 算法练习-右旋字符串(思路+流程图+代码)

            难度:简单         分类:字符串         难度与分类由我所参与的培训课程提供,但需要注意的是,难度与分类仅供参考。以下内容均为个人笔记,旨在督促自己认真学习。         字符串的【右旋转】操作是把字符串尾部的若干个字符转移到字符串的前

    2024年01月22日
    浏览(40)
  • 4、长度最小的子数组

            找到一个数组中,有多少个连续元素的和小于某个值,求出连续元素的长度的最小值。         其本质也是快慢指针,一个指针指向窗口的起始位置,另一个指针指向窗口的终止位置。     1.定义快慢指针: 2.更新慢指针: 并记录长度 3. 更新快指针: 4.重复第二步

    2024年02月14日
    浏览(30)
  • 209. 长度最小的子数组

    给定一个含有  n   个正整数的数组和一个正整数  target  。 找出该数组中满足其和   ≥ target   的长度最小的  连续子数组   [numsl, numsl+1, ..., numsr-1, numsr]  ,并返回其长度 。 如果不存在符合条件的子数组,返回  0  。 示例 1: 示例 2: 示例 3: 提示: 1 = target = 109 1 =

    2024年02月16日
    浏览(34)
  • 【每日算法 && 数据结构(C++)】—— 03 | 合并两个有序数组(解题思路、流程图、代码片段)

    An inch of time is an inch of gold, but you can’t buy that inch of time with an inch of gold. An inch of time is an inch of gold, but you can\\\'t buy that inch of time with an inch of gold 给你两个有序数组,请将两个数组进行合并,并且合并后的数组也必须有序 这个题目要求将两个有序数组合并成一个有序数组。在数

    2024年02月11日
    浏览(55)
  • 【每日算法 && 数据结构(C++)】—— 02 | 数组的并交集(解题思路、流程图、代码片段)

    When you feel like giving up, remember why you started. 当你想放弃时,请记住为什么你开始 给你两个数组,请分别求出两个数组的交集和并集 在数学中,我们可以通过交集和并集来描述两个集合之间的关系。 交集(Intersection) :指的是两个集合中共有的元素组成的集合。可以用符号

    2024年02月11日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包