持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第 16 天,点击查看活动详情。
和至少为 K 的最短子数组
原题地址
给你一个整数数组 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 <=<= nums[i] <=1 <= k <=
思路分析
- 题目中要求子数组的和不能小于
k,并且是连续的; - 我们知道对于一个含有非负数的数组来说,记 为前i项的和,那么按照前面的条件来说,一定会存在 ,那么题目可以转换为需要求 ,且
j-i最小的值; - 使用数组来存储滑动窗口的值,每次循环时在数组中添加此次循环的下标,按照
res.length !== 0 && arr[j] - arr[res[0]] >= k的条件来确定新一轮的滑动窗口的初始值; - 等到循环遍历结束,判断得到的
min值「因为初值为nums.length + 1」,若小于nums.length+1则说明存在这样的子数组,否则不存在返回-1。
AC 代码
/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
var shortestSubarray = function(nums, k) {
let arr = new Array(nums.length + 1).fill(0)
for(let i=0; i < nums.length; i++){
arr[i + 1] = arr[i] + nums[i]
}
let res = [], min = nums.length + 1
for(let j = 0; j < arr.length; j++){
// 上次的和大于本次,即sum[j-1]>arr[j],则不存取
while(res.length !== 0 && arr[res[res.length - 1]] >= arr[j]){
res.pop()
}
while(res.length !== 0 && arr[j] - arr[res[0]] >= k){
// 当本次的sum[j]>arr,则寻找获取最小长度
min = Math.min(j - res[0], min)
// 删除滑动窗口初始值,滑动窗口上次结束值为初始值,当前j为滑动窗口结束值
res.shift()
}
res.push(j)
}
return min < nums.length + 1 ? min : -1
};
结果:
- 执行结果: 通过
- 执行用时:2468 ms, 在所有 JavaScript 提交中击败了19.44%的用户
- 内存消耗:55.8 MB, 在所有 JavaScript 提交中击败了58.33%的用户
- 通过测试用例:97 / 97