leetcode 面试经典 150 题:长度最小的子数组

链接 长度最小的子数组
题序号 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

  • 示例 3:

    输入:target = 11, nums = [1,1,1,1,1,1,1,1]

    输出:0

  • 提示:

    1 <= target <= 10^9^

    1 <= nums.length <= 10^5^

    1 <= nums[i] <= 10^4^

  • 进阶:

    如果你已经实现 O(n) 时间复杂度的解法, 请尝试设计一个 O(n log(n)) 时间复杂度的解法。

题解

滑动窗口法

  1. 子数组:是数组中连续的、非空元素序列。

  2. 核心要点

    • 滑动窗口:使用滑动窗口(双指针)的方法来解决这个问题。定义两个指针 left 和 right,分别表示子数组的开始和结束位置。
    • 窗口和:维护一个变量 sum,表示当前窗口内元素的和。
    • 窗口移动:当 sum < s 时,移动 right 指针向右扩展窗口,并将 nums[right] 加入 sum。当 sum ≥ s 时,记录当前窗口的长度,并尝试移动 left 指针向右缩小窗口,同时从 sum 中减去 nums[left]。
    • 最小长度:在每次满足 sum ≥ s 时,更新最小长度的记录。
  3. 时间复杂度:O(n),因为每个元素最多被访问两次(一次被 right 指针访问,一次被 left 指针访问)。

  4. 空间复杂度:O(1),因为只使用了常数级别的额外空间

  5. c++ 实现算法

cpp 复制代码
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n = nums.size();
        int left = 0; // 滑动窗口左边界
        int sum = 0;  // 当前窗口的总和
        int minLength = INT_MAX; // 最小子数组长度,初始化为无穷大

        for (int right = 0; right < n; ++right) {
            sum += nums[right]; // 将当前元素加入窗口

            // 当窗口内的和满足 >= target 时,尝试缩小窗口
            while (sum >= target) {
                minLength = min(minLength, right - left + 1); // 更新最小长度
                sum -= nums[left]; // 从窗口中移除左边界的值
                ++left; // 左边界右移
            }
        }

        // 如果没有找到符合条件的子数组,返回 0
        return minLength == INT_MAX ? 0 : minLength;
    }
};
  1. 演示 :以示例1为例

  2. c++完整demo

cpp 复制代码
#include <iostream>
#include <vector>
#include <climits> // for INT_MAX
using namespace std;

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n = nums.size();
        int left = 0; // 滑动窗口左边界
        int sum = 0;  // 当前窗口的总和
        int minLength = INT_MAX; // 最小子数组长度,初始化为无穷大

        for (int right = 0; right < n; ++right) {
            sum += nums[right]; // 将当前元素加入窗口

            // 当窗口内的和满足 >= target 时,尝试缩小窗口
            while (sum >= target) {
                minLength = min(minLength, right - left + 1); // 更新最小长度
                sum -= nums[left]; // 从窗口中移除左边界的值
                ++left; // 左边界右移
            }
        }

        // 如果没有找到符合条件的子数组,返回 0
        return minLength == INT_MAX ? 0 : minLength;
    }
};

int main() {
    Solution solution;
    vector<int> nums = {2, 3, 1, 2, 4, 3};
    int target = 7;

    int result = solution.minSubArrayLen(target, nums);
    cout << "result: " << result << endl; // 输出 2
    return 0;
}

滑动窗口法和双指针法

滑动窗口和双指针是解决数组和字符串问题中常用的两种技术,它们在某些情况下可以相互转换,但它们的概念和应用场景有所不同。下面我将分别解释这两种技术,并说明它们的主要区别。

滑动窗口

滑动窗口是一种处理 固定长度或动态长度窗口内元素的技术,常用于解决需要在连续子数组或子字符串中寻找特定属性的问题。 滑动窗口的核心思想是维护一个窗口,随着遍历的进行,窗口内包含的元素会不断变化。

特点:

  • 窗口可以是固定长度,也可以是动态变化的。
  • 窗口内的操作通常是累加、累乘或者比较。
  • 滑动窗口可以用于寻找子数组或子字符串的最大/最小值、和、乘积等。

应用场景:

  • 寻找子数组的和或乘积满足特定条件的最小/最大长度。
  • 判断子数组是否包含特定数量的不同元素。
  • 实现一些需要连续性条件的数据流统计。

双指针

双指针技术通常涉及两个指针(或索引),它们在数组或字符串中以不同的速度移动,用于解决需要比较元素之间相对位置的问题。

特点:

  • 两个指针可以同时移动,也可以一个快一个慢。
  • 双指针常用于比较、排序、去重、寻找特定模式等问题。
  • 双指针可以用于解决有序数组中的特定问题,如寻找两个数的和、差等。

应用场景:

  • 寻找两个指针之间的特定关系,如两数之和为特定值。
  • 判断一个数组是否为回文(快慢指针相向而行)。
  • 实现归并排序、快速排序中的合并和分区步骤。

区别

  • 窗口大小:滑动窗口通常有一个明确的窗口大小,而双指针不一定有固定的大小概念。
  • 移动方式:滑动窗口通常是单向移动(如向右扩展),而双指针可以相向而行或同向而行。
  • 问题类型:滑动窗口更适合解决需要连续性的问题,而双指针更适合解决需要比较元素相对位置的问题。
  • 灵活性:双指针在某些情况下比滑动窗口更灵活,因为它们可以独立控制每个指针的移动。

在实际应用中,滑动窗口和双指针可以根据问题的具体需求相互转换。例如,滑动窗口问题可以通过设置两个指针来模拟,而某些双指针问题也可以通过扩展窗口来解决。理解这两种技术的核心思想和适用场景,可以帮助你更有效地解决算法问题。

相关推荐
打不了嗝 ᥬ᭄5 分钟前
P8795 [蓝桥杯 2022 国 A] 选素数
算法·leetcode·职场和发展·蓝桥杯·图论
serenity宁静7 分钟前
Focal Loss损失函数理解
人工智能·算法·机器学习
窜天遁地大吗喽10 分钟前
abc 384 D(子数组->前缀和) +E(bfs 扩展的时候 按照数值去扩展)
算法
Liknana32 分钟前
unique_ptr 智能指针
c++·算法
Sol-itude1 小时前
【项目介绍】基于机器学习的低空小、微无人机识别技术
人工智能·算法·机器学习·matlab·无人机
友培1 小时前
工业大数据分析算法实战-day08
算法·数据挖掘·数据分析
诚丞成1 小时前
模拟篇——算法浮世绘,探寻模拟之境的计算艺术(2)
c++·算法
毒丐1 小时前
深入解析二叉树算法
数据结构·算法
LuckyRich11 小时前
【贪心算法】贪心算法六
算法·贪心算法
潜意识起点2 小时前
【潜意识Java】蓝桥杯算法有关的动态规划求解背包问题
算法·蓝桥杯·动态规划