当前位置: 首页 > article >正文

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 <= 109
    1 <= nums.length <= 105
    1 <= nums[i] <= 104

  • 进阶:
    如果你已经实现 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++ 实现算法

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

#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;
}

滑动窗口法和双指针法

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

滑动窗口

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

特点:

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

应用场景:

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

双指针

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

特点:

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

应用场景:

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

区别

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

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


http://www.kler.cn/a/446495.html

相关文章:

  • 鸿蒙开发(18)arkTS类型
  • [JavaScript] 我该怎么去写一个canvas游戏
  • JNDI基础
  • [Python学习日记-73] 面向对象实战1——答题系统
  • linux java 查看异常堆栈
  • 空天地遥感数据识别与计算--数据分析如何助力农林牧渔、城市发展、地质灾害监测等行业革新
  • HCIA/HCIP/HCIE的报名官网
  • Python中bs4库的详细介绍
  • 多个Echart遍历生成 / 词图云
  • 相机内外参知识
  • 【Rust自学】4.4. 引用与借用
  • Golang学习历程【第三篇 基本数据类型类型转换】
  • idea部署maven项目步骤(图+文)
  • 深入理解 JVM 垃圾回收机制
  • Neo4j【环境部署 02】图形数据库Neo4j在Linux系统ARM架构下的安装使用
  • MacPorts 中安装高/低版本软件方式,以 RabbitMQ 为例
  • 《基于 Python 的网页爬虫详细教程》
  • 便捷就医新引擎:SSM 医院预约挂号系统 Vue 实现方案设计
  • wpf mvvm 数据绑定数据(按钮文字表头都可以),根据长度进行换行,并把换行的文字居中
  • 利用Python爬虫快速获取商品历史价格信息
  • SSM+Vue 驱动的电脑测评系统:诠释科技评测新高度
  • 开源云原生数据仓库ByConity ELT 的测试体验
  • [每周一更]-(第128期):CentOS源码安装PostgreSQL
  • vue-router的详细安装及配置
  • 2024年11月 蓝桥杯青少组 STEMA考试 Scratch真题
  • 12.13-12.21 刷题汇总