Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 9ad7c09

Browse files
committed
Create 0862. 和至少为 K 的最短子数组.md
1 parent 0209deb commit 9ad7c09

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# [0862. 和至少为 K 的最短子数组](https://leetcode.cn/problems/shortest-subarray-with-sum-at-least-k/)
2+
3+
- 标签:队列、数组、二分查找、前缀和、滑动窗口、单调队列、堆(优先队列)
4+
- 难度:困难
5+
6+
## 题目链接
7+
8+
- [0862. 和至少为 K 的最短子数组 - 力扣](https://leetcode.cn/problems/shortest-subarray-with-sum-at-least-k/)
9+
10+
## 题目大意
11+
12+
**描述**:给定一个整数数组 $nums$ 和一个整数 $k$。
13+
14+
**要求**:找出 $nums$ 中和至少为 $k$ 的最短非空子数组,并返回该子数组的长度。如果不存在这样的子数组,返回 $-1$。
15+
16+
**说明**:
17+
18+
- **子数组**:数组中连续的一部分。
19+
- 1ドル \le nums.length \le 10^5$。
20+
- $-10^5 \le nums[i] \le 10^5$。
21+
- 1ドル \le k \le 10^9$。
22+
23+
**示例**:
24+
25+
- 示例 1:
26+
27+
```python
28+
输入:nums = [1], k = 1
29+
输出:1
30+
```
31+
32+
- 示例 2:
33+
34+
```python
35+
输入:nums = [1,2], k = 4
36+
输出:-1
37+
```
38+
39+
## 解题思路
40+
41+
### 思路 1:前缀和 + 单调队列
42+
43+
题目要求得到满足和至少为 $k$ 的子数组的最短长度。
44+
45+
先来考虑暴力做法。如果使用两重循环分别遍历子数组的开始和结束位置,则可以直接求出所有满足条件的子数组,以及对应长度。但是这种做法的时间复杂度为 $O(n^2)$。我们需要对其进行优化。
46+
47+
#### 1. 前缀和优化
48+
49+
首先对于子数组和,我们可以使用「前缀和」的方式,方便快速的得到某个子数组的和。
50+
51+
对于区间 $[left, right],ドル通过 $pre\underline{}sum[right + 1] - prefix\underline{}cnts[left]$ 即可快速求解出区间 $[left, right]$ 的子数组和。
52+
53+
此时问题就转变为:是否能找到满足 $i > j$ 且 $pre\underline{}sum[i] - pre\underline{}sum[j] \ge k$ 两个条件的子数组 $[j, i)$?如果能找到,则找出 $i - j$ 差值最小的作为答案。
54+
55+
#### 2. 单调队列优化
56+
57+
对于区间 $[j, i)$ 来说,我们应该尽可能的减少不成立的区间枚举。
58+
59+
1. 对于某个区间 $[j, i)$ 来说,如果 $pre\underline{}sum[i] - pre\underline{}sum[j] \ge k,ドル那么大于 $i$ 的索引值就不用再进行枚举了,不可能比 $i - j$ 的差值更优了。此时我们应该尽可能的向右移动 $j,ドル从而使得 $i - j$ 更小。
60+
2. 对于某个区间 $[j, i)$ 来说,如果 $pre\underline{}sum[j] \ge pre\underline{}sum[i],ドル对于任何大于等于 $i$ 的索引值 $r$ 来说,$pre\underline{}sum[r] - pre\underline{}sum[i]$ 一定比 $pre\underline{}sum[i] - pre\underline{}sum[j]$ 更小且长度更小。此时 $pre\underline{}sum[j]$ 可以直接忽略掉。
61+
62+
因此,我们可以使用单调队列来保存单调递增的 $pre\underline{}sum[x]$ 值的下标。
63+
64+
对于每一个位置 $i$ 我们可以判断其之前存入在单调队列中的 $pre\underline{}sum[j]$ 值,如果 $pre\underline{}sum[i] - pre\underline{}sum[j] \ge k,ドル则更新答案,并将 $j$ 从队头位置弹出。直到 $pre\underline{}sum[i] - pre\underline{}sum[j] < k$ 时为止。
65+
66+
如果队尾 $pre\underline{}sum[j] \ge pre\underline{}sum[i],ドル那么 $$
67+
68+
使用一重循环遍历 $i,ドル对于 $pre\underline{}sum[i],ドル我们希望使用某个数据结构,能够使得在满足 $pre\underline{}sum[i] - pre\underline{}sum[j] \ge k$ 当前前提下,能够尽可能的向右移动 $j,ドル从而使得 $i - j$ 最小。
69+
70+
### 思路 1:代码
71+
72+
```Python
73+
class Solution:
74+
def shortestSubarray(self, nums: List[int], k: int) -> int:
75+
size = len(nums)
76+
77+
pre_sum = [0 for _ in range(size + 1)]
78+
for i in range(size):
79+
pre_sum[i + 1] = pre_sum[i] + nums[i]
80+
81+
ans = float('inf')
82+
queue = collections.deque()
83+
84+
for i in range(size + 1):
85+
# 优化 1
86+
while queue and pre_sum[i] - pre_sum[queue[0]] >= k:
87+
ans = min(ans, i - queue.popleft())
88+
# 优化 2
89+
while queue and pre_sum[queue[-1]] >= pre_sum[i]:
90+
queue.pop()
91+
queue.append(i)
92+
93+
if ans == float('inf'):
94+
return -1
95+
return ans
96+
```
97+
98+
### 思路 1:复杂度分析
99+
100+
- **时间复杂度**:$O(n),ドル其中 $n$ 为数组 $nums$ 的长度。
101+
- **空间复杂度**:$O(n)$。
102+

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /