夯实算法-长度最小的子数组

111 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 21 天,点击查看活动详情

题目:LeetCode

给定一个含有 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<=1091 <= target <= 10^9
  • 1<=nums.length<=1051 <= nums.length <= 10^5
  • 1<=nums[i]<=1051 <= nums[i] <= 10^5

解题思路

根据题意分析:

for循环遍历输入数组nums的元素,控制决定每次左边界(起点)

  • start=0,子数组有[2 .....]的组合
  • start=1,子数组有[3 .....]的组合

每次固定好左边界,循环内部利用二分查找找到第一个使得子数组的和(结束点~起点 范围) >=target 的下标位置

  • 利用前缀和数组sums,子数组和 = sums[结束点+1] - sums[起点]

    • 如数组[2, 3, 1, 2, 4, 3],求其[3, 1, 2]子数组的和,即前4个元素的和 - 前1个元素的和, sums[4] - sums[1]=8-2=6
  • 二分方式

    • 如子数组和sum<target,还可以扩大右边界,因此往右边区间二分
    • 如子数组和sum>=target,往左边区间逼近
    • 注意过程中可能最后都找不到满足target的子数组和,所以最后还要确认一遍子数组和,如果满足>=target就更新结果最小值

代码实现

public int minSubArrayLen(int target, int[] nums) {
    int res = Integer.MAX_VALUE;
    int[] sums = new int[nums.length + 1];
    // sums[1] - sum of the first element
    // sums[2] - sum of all first 2 elements
    for (int i = 1; i < sums.length; i++) {
        sums[i] = sums[i - 1] + nums[i - 1];
    }
    for (int start = 0; start < nums.length; start++) {
        int left = start, right = nums.length - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            int sum = sums[mid + 1] - sums[start];
            if (sum < target) {
                // move to the right interval
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        //double check - in case the target hasn't been found
        if (sums[right + 1] - sums[start] >= target) {
            res = Math.min(res, right - start + 1);
        }
    }
    return res == Integer.MAX_VALUE ? 0 : res;
}

运行结果

Snipaste_2023-02-24_22-49-34.png

复杂度分析

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

掘金(JUEJIN)  一起分享知识, Keep Learning!