LeetCode题目209 长度最小的子数组

题目分析

在这里插入图片描述


题目分析

针对一个数组求符合长度长度最小的连续子数组。在数组或者字符串中根据约束条件求满足条件的连续数组,很明显可以通过滑动窗口的方法来解决。


解法一:滑动窗口

滑动窗口的代码如下,基本的滑动窗口套路

public int minSubArrayLen(int target, int[] nums) {
        //窗口左边界
        int left = 0;
        //窗口右边界
        int right = 0;
        //窗口中当前和
        int curSum = 0;
        //最小长度值
        int minLen = Integer.MAX_VALUE;
        while(right < nums.length){
            //累加
            curSum += nums[right];
            //当满足题目中的约束条件时 缩小窗口 即增加左边界的值
            while (curSum >= target){
                minLen = Math.min(minLen, right - left + 1);
                curSum -= nums[left];
                left++;
            }
            right++;
        }
        //判断是否有符合条件的值 存在则返回 不存在返回0
        return minLen == Integer.MAX_VALUE ? 0 : minLen;
    }

时间复杂度:O(n),其中n是数组的长度,right和left最多移动n次。
空间复杂度:O(1)

解法二:前缀和 + 滑动窗口

题目还有个进阶,即是否可以尝试在时间复杂度O(nlog(n))解决,看到时间复杂度设计到log(n),题目又涉及到数组,那么肯定是用二分查找,但是二分查找的数组必须有序,原来的数组无序,怎么用二分查找呢?分析题目,发现题目是求和,那能不能用前缀和呢?题目的约束条件是数组中的每个数字都是正数,因此,数组的前缀和数组一定是有序的。因此可以利用前缀和+二分查找来求解。参考leetcode官方题解代码,代码示例如下:

public int minSubArrayLen(int target, int[] nums) {
      //前缀和数组
        int length = nums.length;
        int[] sum = new int[length + 1];
        int ans = Integer.MAX_VALUE;
        //前缀和数组求解
        for(int i = 1; i <= length; ++i){
            sum[i] = sum[i - 1] + nums[i - 1];
        }
        for(int i = 1; i <= length; ++i){
            int sumValue = target + sum[i-1];
            //找到前缀和数组中等于或者比sumValue大的第一个元素
            int bound = Arrays.binarySearch(sum, sumValue);
            if(bound < 0){
                bound = -bound - 1;
            }
            //sum的长度是length+1 当找不到的时候返回的是length+2
            //处理后等于length+1  因此这个位置一定返回的是false
            if(bound <= length){
                ans = Math.min(ans, bound - (i - 1));
            }
        }
        return ans == Integer.MAX_VALUE ? 0 : ans;
    }

虽然这种解法相比滑动窗口的解法复杂度增加了,但是为我们提供了一种新的思路,即看到log(n),联想到二分,联想到有序,进而联想到前缀和,最终可以写出上述解法。


Java中Arrays.binarySearch()用法

上面解法二用到了Arrays.binarySearch()这个api,之前只知道是在数组中对于目标数字进行二分查找,并且只在目标值存在的情况下使用,今天在理解解法二的时候,发现在目标值不存在的时候,返回值很有趣,之前没有记录过,特意记录下:

  • 如果该值存在 则直接返回下标索引
  • 如果该值不存在,返回第一个比目标值大的位置的索引值(但是此时,索引值的计算从0开始)的相反数

简单代码测试如下:

int[] info = {1,2,3,4,5,8,9};
        //存在 则返回目标值的索引值 2
        System.out.println(Arrays.binarySearch(info, 3));
        //不存在 返回第一个必它大的值的索引
        // 此时是8,但是索引从1开始计算,则索引是5+1=6
        //返回相反数 所以输出-6
        System.out.println(Arrays.binarySearch(info, 7));
        //不存在 返回第一个必它大的值的索引
        // 数组中不存在任何比它还大的值 则直接返回数组的长度 + 1 = 7 + 1 = 8
        //返回相反数 所以输出-8
        System.out.println(Arrays.binarySearch(info, 10));

总结

如有错误,恳请大家批评指正,日拱一卒,功不唐捐。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值