“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情”
题目描述
题目分析
粗略一看题目,这不就是一个很简单的问题吗?我直接一个双重for循环每次求出从i到j的累加和,内层循环每次取最短长度不就出来了,于是上代码:
var minSubArrayLen = function(target, nums) {
let res = nums.length + 1;
let len = 0;
let sum = 0;
for (let i = 0; i < nums.length; i++) {
sum = 0;
for (let j = i; j < nums.length; j++) {
sum += nums[j];
if (sum >= target) {
len = j - i + 1;
res = Math.min(len, res);
break
}
}
}
return res > nums.length ? 0 : res;
}
然后信心百倍的提交运行,不出意外通过了,就是时间优点长,我都想炫耀一下了。
那么是不是可以优化一下呢,如果就这么简单就过了,应该不会定义为中等难度,显然这不是出题者想要考察的内容,面试遇到你要是直接写出这样的答案,估计面试官就直接喊你回家了:“HR你叫人来面试都不筛选的吗?这都是些什么妖魔鬼怪!”
于是,为了不被面试官连人带椅子抬出去,我仔细思考了10分钟,感觉应该用滑动窗口,但总是差点东西,又写了10分钟,还是没写出来,果断看题解,瞬间豁然开朗,关掉题解,又是10分钟过去了。
然后再老老实实的把题解背了一遍,这里贴上滑动窗口的定义,所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。首先我们要明白三点:
1.滑动窗口的内容是什么?满足条件的最小子数组的长度
2.滑动窗口的起始位置?窗口的个端点
3.何时该移动起始位置?当窗口的累计和大于等于目标值时,应该移动左端点;小于目标值时,应该移动右端点
所以可以得出窗口移动时候的伪代码:
1.计算窗口长度
2.判断当前窗口长度与上一轮循环后的最小值大小,取最小值
3.当前窗口累加和减去开始端点值,起点右移
代码实现
var minSubArrayLen = function(target, nums) {
// // 滑动窗口解法
let sum = 0; // 累加和
let len = nums.length+1; // 最小长度
let currentLen = 0 // 当前最小长度
let i = 0 ; // 滑动窗口起点
for(let j=0;j<nums.length;j++){ // j表示滑动窗口终点
sum += nums[j]
while(sum>=target){ // 累加和大于目标值 ,说明左边改移动了
currentLen = j - i + 1 // 当前子数组长度
len = currentLen < len ? currentLen:len
sum -= nums[i]
i++ // 起始右移
}
console.log(len)
}
return len > nums.length ? 0 :len
};