刷题日记——长度最小的子数组

53 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情

今天来刷的题依旧是关于数组的。

209.长度最小的子数组

力扣题目链接(opens new window)

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

示例:

输入:s = 7, nums = [2,3,1,2,4,3] 输出:2 解释:子数组 [4,3] 是该条件下的长度最小的子数组。

暴力解法

先暴力解一遍,没啥技巧,很显然时间复杂度是O(n^2),设置了双层for循环,外层用于遍历数组寻找起始元素,内层用于计算数组元素和。同样的,这种解法在力扣是不通过的,因为超出时间限制了。

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int cnt=99999;
        for(int i=0;i<nums.length;i++){
            int sum=0;
            int cnt1=0;
            for(int j=i;j<nums.length;j++){
                sum+=nums[j];
                if(sum>=target){
                    cnt1=j-i+1;
                    cnt=cnt1<cnt ? cnt1:cnt;
                    break;
                }
            }
        }
        return cnt==99999? 0:cnt;
    }
}

滑动窗口

简单来说就还是双指针; 我们将j放在for循环中,作为窗口的右边界,遍历数组;而i作为窗口的左边界,当数组之和大于等于目标值时,才让i加一,这时要记住,要把sum也减去nums[i],因为他已经不包含在我们的窗口中了。

又学到一种写法,关于int的最大值

int cnt = Integer.MAX_VALUE;

滑动窗口的精妙之处就在于根据当前子序列和大小的情况,能够不断调节子序列的起始位置。从而将时间复杂度为O(n^2)的暴力解法降为O(n)。

代码如下

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int cnt=Integer.MAX_VALUE;
        int i=0,sum=0,cnt1=0;
        for(int j=0;j<nums.length;j++){
            sum+=nums[j];
            while(sum>=target){
                cnt1=j-i+1;
                cnt= cnt1<cnt? cnt1:cnt;
                sum-=nums[i];
                i++;
            }
        }
        return cnt==Integer.MAX_VALUE? 0:cnt;
    }
}

滑动窗口的难点主要就在于如何移动窗口的起始位置和结束位置,这里我们只用一个for循环就巧妙解决了,主要就是起始位置的移动变换了方式。

还有一点就是关于代码中为什么用while(sum>=target)而不是用if(sum>=target),这是因为我们将窗口起始位置往前移动一位后,可能总和依旧大于目标值,就需要我们继续把i往前移动,这样只用if是做不到的,if只能移动一次,而用while则可以一直移动到满足条件为止。

以上就是这道题需要注意的点,这道题不是很难,重点就是滑动窗口的思路。