给定一个含有 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;
}