Leetcode209-长度最小的子数组[两种方法] 关键词 滑窗 二分答案 前缀和

文章目录

  • 前言
  • 题目
  • [方法一:滑窗 O(n)](#方法一:滑窗 O(n))
  • [方法二:二分答案 O(nlogn)](#方法二:二分答案 O(nlogn))

前言

  1. 左闭右开是编程中表示一段区间的最规范的方式
  2. 二分查找的正确打开方式为
cpp 复制代码
        int lo = 0, hi = n, mi;
        while (lo < hi) {
            mi = (lo + hi) / 2;
            if (k < sum[mi])
                hi = mi;
            else
                lo = mi + 1;
        }
        return lo - 1;
  1. O(nlogn)的算法不一定比O(n)的算法慢

题目


方法一:滑窗 O(n)

滑窗处理"最长子列"问题,就是左端在迫不得已的时候才收缩;

滑窗处理"最短子列"问题,就是左端积极收缩,只要有能使窗口变小的可能,就积极尝试。

本题就是后者:滑窗右端每向右挪一个元素,尝试收缩左端。

cpp 复制代码
class Solution {
    int sum = 0; // 滑窗内的数值总和
    int min(int a, int b) { return a < b ? a : b; }

public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int pl = 0, pr = 0, ans = 200000;
        // [pl, pr)左闭右开区间
        while (pr < nums.size()) {
            sum += nums[pr];
            pr++;

            if (sum < target)
                continue;

            while (sum - nums[pl] >= target) {
                sum -= nums[pl];
                pl++;
            }
            ans = min(ans, pr - pl);
        }
        return ans == 200000 ? 0 : ans;
    }
};

方法二:二分答案 O(nlogn)

预处理好前缀和之后,对于每一个右边界,二分找到对应的左边界。

cpp 复制代码
class Solution {
    int sum[100010]; // 前缀和
    int min(int a, int b) { return a < b ? a : b; }
    int find(int n, int k) // n个元素,返回值小于等于k的最后一个元素的下标
    {
        int lo = 0, hi = n, mi; // lo hi左闭右开
        while (lo < hi) {
            mi = (lo + hi) / 2;
            if (k < sum[mi])
                hi = mi;
            else
                lo = mi + 1;
        }
        return lo - 1;
    }

public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int pl = 0, pr = 0, ans = 200000;
        sum[0] = 0;
        for (int i = 0; i < nums.size(); i++)
            sum[i + 1] = sum[i] + nums[i];

        for (int i = 1; i < nums.size() + 1; i++) {
            int pos = find(nums.size() + 1, sum[i] - target);
            if (pos < 0)
                continue;
            ans = min(ans, i - pos);
        }

        return ans == 200000 ? 0 : ans;
    }
};
相关推荐
LYFlied5 小时前
【每日算法】LeetCode 153. 寻找旋转排序数组中的最小值
数据结构·算法·leetcode·面试·职场和发展
唐装鼠5 小时前
rust自动调用Deref(deepseek)
开发语言·算法·rust
ytttr8736 小时前
MATLAB基于LDA的人脸识别算法实现(ORL数据库)
数据库·算法·matlab
jianfeng_zhu8 小时前
整数数组匹配
数据结构·c++·算法
yueqingll8 小时前
032、数据结构之代码时间复杂度和空间复杂度的判断:从入门到实战
数据结构
smj2302_796826528 小时前
解决leetcode第3782题交替删除操作后最后剩下的整数
python·算法·leetcode
LYFlied9 小时前
【每日算法】LeetCode 136. 只出现一次的数字
前端·算法·leetcode·面试·职场和发展
唯唯qwe-9 小时前
Day23:动态规划 | 爬楼梯,不同路径,拆分
算法·leetcode·动态规划
做科研的周师兄10 小时前
中国土壤有机质数据集
人工智能·算法·机器学习·分类·数据挖掘
来深圳10 小时前
leetcode 739. 每日温度
java·算法·leetcode