LeetCode刷题之209. 长度最小的子数组

63 篇文章 0 订阅
13 篇文章 0 订阅

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

示例 1:

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

解法一:

先用我们最喜欢的暴力解下。 首先可以先把一个元素定死,也就是外层for循环来表示从谁开始,然后开始,在内层一点点判断nums[j]+nums[j+1]...nums[length-1]其中某个子集是否大于target,大于的话直接内层就可以break了,由于是从短到长的,找到短的就没必要管长的了。

下面是代码:

public int minSubArrayLen(int target, int[] nums) {
        int n = nums.length;
        if (n == 0) {//长度为零直接返回0
            return 0;
        }
        int ans = Integer.MAX_VALUE;
        for (int i = 0; i < n; i++) {
            int sum = 0;
            for (int j = i; j < n; j++) {
                sum += nums[j];
                if (sum >= target) {
                    ans = Math.min(ans, j - i + 1);
                    break;
                }
            }
        }
        return ans == Integer.MAX_VALUE ? 0 : ans;
    }

解法二:

这次我们采取双指针,声明一个sum=0 定义两个指针low和high,分别指向加进sum的数的下标的首和尾,先让high指针动起来,把数组中的元素一个一个往sum加,当sum>=target停止,说明前面的子序列已经达到要求更新min的值,但我们并不道刚加进来的数到底有多大,不确定大小,但最初的数已经判断过了,所以我们可以让low动起来,往前挪, 如果仍然大于target可以更新min值,如果小于target,就继续让high动起来,重复上面操作,直到high>nums.length-1,结束循环。返回min。

下面上代码:

 public int minSubArrayLen(int target, int[] nums) {
          int n=nums.length;
          if(n==0){
              return 0;
          }
          int min=Integer.MAX_VALUE,low=0,high=0;
          int sum=0;
          while(high<n){
              sum+=nums[high++];//high++先执行high在++

              while(sum>=target){
                  min=Math.min(min,high-low);
                  sum-=nums[low++];
              }
          }

          return Integer.MAX_VALUE==min?0:min;
          
    }

解法三

哎这是一个二分题,还是按题意来,咱们用二分解决下。二分是针对有序数组判断的,可是题目中的数组,确实无序的,我们需要找到的一个有序的条件,恰巧他们子序列的和是递增的,这样我们就可以用二分了,子序列的和必须用第一列,第一列包含了每个元素。申请的数组下标就对应这目标元素数量的和。例如:sum[0]=0,sum[1]=sum[0]+nums[0],当我们建好子序列和的数组后,我们就可以开始用二分了,只要找到sum[j]-sum[i]>target,可以换下位sum[j]>sum[i]+target,只要sum[i]+target在子序列和的一个边界,因为二分如果找不到数时left和right停在一个比他大和比他小的这个范围上,具体停在哪根据条件而定,根据这个特性,就可以得到这个字序列,j-i+1就是这个序列的长度,更新min。然后重复上面操做,最后min的值就是答案,但需要分析下边界。

下面是代码:

    public int minSubArrayLen(int target, int[] nums) {
       int[] sum=new int[nums.length+1];
       int min=Integer.MAX_VALUE; 
       for(int i=1;i<=nums.length;i++){
            sum[i]=sum[i-1]+nums[i-1];
       }
       
       for(int j=0;j<sum.length;j++){

           int index=target+sum[j];
           int k=Arrays.binarySearch(sum,index);

           if(k<0){//binarySearch找不到的是返回-(low+1)
               k = ~k;//按位取反
           }
           if(k<=nums.length){//k超过length就说明不存在比target大的子序列
                min=Math.min(k-j,min);
           }
     }

       return min==Integer.MAX_VALUE?0:min;
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值