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] <= 105
进阶:
- 如果你已经实现
O(n)
时间复杂度的解法, 请尝试设计一个O(n log(n))
时间复杂度的解法。
方法一:前缀和 + 二分查找
我们先预处理出数组
接下来,我们遍历前缀和数组
最后,如果
时间复杂度
java
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int n = nums.length;
long[] s = new long[n + 1];
for (int i = 0; i < n; ++i) {
s[i + 1] = s[i] + nums[i];
}
int ans = n + 1;
for (int i = 0; i <= n; ++i) {
int j = search(s, s[i] + target);
if (j <= n) {
ans = Math.min(ans, j - i);
}
}
return ans <= n ? ans : 0;
}
private int search(long[] nums, long x) {
int l = 0, r = nums.length;
while (l < r) {
int mid = (l + r) >> 1;
if (nums[mid] >= x) {
r = mid;
} else {
l = mid + 1;
}
}
return l;
}
}
cpp
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int n = nums.size();
vector<long long> s(n + 1);
for (int i = 0; i < n; ++i) {
s[i + 1] = s[i] + nums[i];
}
int ans = n + 1;
for (int i = 0; i <= n; ++i) {
int j = lower_bound(s.begin(), s.end(), s[i] + target) - s.begin();
if (j <= n) {
ans = min(ans, j - i);
}
}
return ans <= n ? ans : 0;
}
};
ts
function minSubArrayLen(target: number, nums: number[]): number {
const n = nums.length;
const s: number[] = new Array(n + 1).fill(0);
for (let i = 0; i < n; ++i) {
s[i + 1] = s[i] + nums[i];
}
let ans = n + 1;
const search = (x: number) => {
let l = 0;
let r = n + 1;
while (l < r) {
const mid = (l + r) >>> 1;
if (s[mid] >= x) {
r = mid;
} else {
l = mid + 1;
}
}
return l;
};
for (let i = 0; i <= n; ++i) {
const j = search(s[i] + target);
if (j <= n) {
ans = Math.min(ans, j - i);
}
}
return ans === n + 1 ? 0 : ans;
}
python
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
n = len(nums)
s = list(accumulate(nums, initial=0))
ans = n + 1
for i, x in enumerate(s):
j = bisect_left(s, x + target)
if j <= n:
ans = min(ans, j - i)
return ans if ans <= n else 0
方法二:双指针
我们注意到,数组
具体地,我们定义两个指针
在每一步操作中,我们移动右指针
最后,如果最小长度
时间复杂度
java
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int l = 0, n = nums.length;
long s = 0;
int ans = n + 1;
for (int r = 0; r < n; ++r) {
s += nums[r];
while (s >= target) {
ans = Math.min(ans, r - l + 1);
s -= nums[l++];
}
}
return ans > n ? 0 : ans;
}
}
cpp
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int l = 0, n = nums.size();
long long s = 0;
int ans = n + 1;
for (int r = 0; r < n; ++r) {
s += nums[r];
while (s >= target) {
ans = min(ans, r - l + 1);
s -= nums[l++];
}
}
return ans > n ? 0 : ans;
}
};
ts
function minSubArrayLen(target: number, nums: number[]): number {
const n = nums.length;
let [s, ans] = [0, n + 1];
for (let l = 0, r = 0; r < n; ++r) {
s += nums[r];
while (s >= target) {
ans = Math.min(ans, r - l + 1);
s -= nums[l++];
}
}
return ans > n ? 0 : ans;
}
python
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
l = s = 0
ans = inf
for r, x in enumerate(nums):
s += x
while s >= target:
ans = min(ans, r - l + 1)
s -= nums[l]
l += 1
return 0 if ans == inf else ans