leetcode 209. 长度最小的子数组

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

示例: 

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

如果你已经完成了O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。

方法一:二分,时间复杂度O(nlog(n))
我做这道题的二分法有点绕,主要是边界问题;
首先我写的二分查找是返回大于等于目标数的元素索引,如果目标大于所有值返回-1.

原数组nums = [2,3,1,2,4,3]
前i项和数组sums = [0,2,5,6,8,12,15]
如果从nums的第0项开始找,即找[2,3,1,2] = 8 > 7,也就是nums的第0,1,2,3项,
那么怎么用sums的数组表示呢,nums从第0项开始对应sums从第一项开始找,
即sums[4] - sums[0] = 8 - 0 = 8,这里sums的第四项就是用二分查找到的,
在这里插入图片描述
若在target大于所有sums中的数字,二分会返回-1,即没有满足的子数组

public class Solution {
    public int minSubArrayLen(int s, int[] nums) {
        if(nums.length == 0){
            return 0;
        }
        int result = Integer.MAX_VALUE;
        int[] sums = new int[nums.length + 1];
        for(int i = 1; i < sums.length; i++){
            sums[i] = sums[i - 1] + nums[i - 1];
        }
        for(int i = 1; i < sums.length; i++){
            int tmp = lowerBound(sums, 0, sums.length, s + sums[i - 1]);
            if(tmp != -1){
                result = Math.min(result, tmp - i + 1);
            }
        }
        if(result == Integer.MAX_VALUE){
            return 0;
        }
        return result;
    }
    private int lowerBound(int[] nums, int L, int R, int target){
        while(L < R){
            int mid = L + (R - L) / 2;
            if(target <= nums[mid]){
                R = mid;
            }
            else{
                L = mid + 1;
            }
        }
        if(L == nums.length) return -1;
        return L;
    }

方法二:双指针,时间复杂度O(n)
左指针指向首元素,右指针不断右移,知道左右指针之间的数和满足要求,记录长度,左指针不断右移,更新长度,直到和不满足要求,再将右指针右移,从而遍历所有子数组。

public class Solution {
    public int minSubArrayLen(int s, int[] nums) {
       int n = nums.length;
       int result = Integer.MAX_VALUE;
       int L = 0, sum = 0;
       for(int i = 0; i < n; i++) {
           sum += nums[i];
           while(sum >= s){
               result = Math.min(result, i + 1 - L);
               sum -= nums[L++];
           }
       }
       return result != Integer.MAX_VALUE ? result : 0;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值