LeetCode 题解工作台

和至少为 K 的最短子数组

给你一个整数数组 nums 和一个整数 k ,找出 nums 中和至少为 k 的 最短非空子数组 ,并返回该子数组的长度。如果不存在这样的 子数组 ,返回 -1 。 子数组 是数组中 连续 的一部分。 示例 1: 输入: nums = [1], k = 1 输出: 1 示例 2: 输入: nums …

category

7

题型

code_blocks

6

代码语言

hub

3

相关题

当前训练重点

困难 · 二分·搜索·答案·空间

bolt

答案摘要

题目要求找到一个最短的子数组,使得子数组的和大于等于 。不难想到,可以使用前缀和快速计算子数组的和。 我们用一个长度为 的数组 表示数组 前 个元素的和。另外,我们需要维护一个严格单调递增的队列 ,队列中存储的是前缀和数组 的下标。注意,这里的单调递增是指下标对应的前缀和的大小,而不是下标的大小。

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 二分·搜索·答案·空间 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给你一个整数数组 nums 和一个整数 k ,找出 nums 中和至少为 k最短非空子数组 ,并返回该子数组的长度。如果不存在这样的 子数组 ,返回 -1

子数组 是数组中 连续 的一部分。

 

示例 1:

输入:nums = [1], k = 1
输出:1

示例 2:

输入:nums = [1,2], k = 4
输出:-1

示例 3:

输入:nums = [2,-1,2], k = 3
输出:3

 

提示:

  • 1 <= nums.length <= 105
  • -105 <= nums[i] <= 105
  • 1 <= k <= 109
lightbulb

解题思路

方法一:前缀和 + 单调队列

题目要求找到一个最短的子数组,使得子数组的和大于等于 kk。不难想到,可以使用前缀和快速计算子数组的和。

我们用一个长度为 n+1n+1 的数组 s[i]s[i] 表示数组 numsnumsii 个元素的和。另外,我们需要维护一个严格单调递增的队列 qq,队列中存储的是前缀和数组 s[i]s[i] 的下标。注意,这里的单调递增是指下标对应的前缀和的大小,而不是下标的大小。

为什么存的是下标呢?这是为了方便计算子数组的长度。那为什么队列严格单调递增?我们可以用反证法来说明。

假设队列元素非严格单调递增,也即是说,存在下标 iijj,满足 i<ji < j,且 s[i]s[j]s[i] \geq s[j]

当遍历到下标 kk,其中 i<j<kni \lt j \lt k \leq n,此时 s[k]s[j]s[k]s[i]s[k]-s[j] \geq s[k]-s[i],且 nums[j..k1]nums[j..k-1] 的长度小于 nums[i..k1]nums[i..k-1] 的长度。由于下标 jj 的存在,子数组 nums[i..k1]nums[i..k-1] 一定不是最优解,队列中的下标 ii 是不必要的,需要将其移除。因此,队列中的元素一定严格单调递增。

回到这道题目上,我们遍历前缀和数组 ss,对于遍历到的下标 ii,如果 s[i]s[q.front]ks[i] - s[q.front] \geq k,说明当前遇到了一个可行解,我们可以更新答案。此时,我们需要将队首元素出队,直到队列为空或者 s[i]s[q.front]<ks[i] - s[q.front] \lt k 为止。

如果此时队列不为空,为了维持队列的严格单调递增,我们还需要判断队尾元素是否需要出队,如果 s[q.back]s[i]s[q.back] \geq s[i],则需要循环将队尾元素出队,直到队列为空或者 s[q.back]<s[i]s[q.back] \lt s[i] 为止。然后,我们将下标 ii 入队。

遍历结束,如果我们没有找到可行解,那么返回 1-1。否则,返回答案。

时间复杂度 O(n)O(n),空间复杂度 O(n)O(n)。其中 nn 是数组 numsnums 的长度。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution:
    def shortestSubarray(self, nums: List[int], k: int) -> int:
        s = list(accumulate(nums, initial=0))
        q = deque()
        ans = inf
        for i, v in enumerate(s):
            while q and v - s[q[0]] >= k:
                ans = min(ans, i - q.popleft())
            while q and s[q[-1]] >= v:
                q.pop()
            q.append(i)
        return -1 if ans == inf else ans
speed

复杂度分析

指标
时间O(n)
空间O(n)
psychology

面试官常问的追问

外企场景
  • question_mark

    Ensure the candidate can efficiently optimize their solution using binary search and sliding window techniques.

  • question_mark

    Look for the use of prefix sums and monotonic queues to avoid unnecessary recalculations.

  • question_mark

    Evaluate their ability to recognize when a solution needs binary search over a valid answer space.

warning

常见陷阱

外企场景
  • error

    Misunderstanding the need for binary search over answer space, which is crucial for optimizing the solution.

  • error

    Forgetting to properly handle the case where no subarray satisfies the sum condition, leading to a wrong answer.

  • error

    Not managing the monotonic queue properly, which can lead to inefficiency or incorrect results.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    What happens if the array contains negative numbers? How does this affect the sliding window approach?

  • arrow_right_alt

    Can this problem be solved using a brute force approach, and what are the trade-offs?

  • arrow_right_alt

    How does the time complexity change if we used a naive method instead of binary search and sliding window?

help

常见问题

外企场景

和至少为 K 的最短子数组题解:二分·搜索·答案·空间 | LeetCode #862 困难