LeetCode,209.长度最小的子数组
/**
- 209.长度最小的子数组
- 给定一个含有 n 个正整数的数组和一个正整数 s ,
- 找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。
- 如果不存在符合条件的子数组,返回 0。
- 示例:
- 输入:s = 7, nums = [2,3,1,2,4,3] 输出:2
- 解释:子数组 [4,3] 是该条件下的长度最小的子数组
*/
滑动窗口解法
/**
* 滑动窗口法(确定一个满足条件的子数组,从头开始依次减少,求出满足条件的最小长度)
* for 循环控制right的位置(left到right为一个满足条件的子数组,在子数组中找出满足条件的最小长度)
* 例如:nums :1,2, 3, 6, 7 ; s = 6
* left = 0; right = 3;时满足条件,但是其实单一个6就满足了,所以此时需要在这个子数组中找满足条件的最小长度
* 步骤:right = 3,是确定了的,此时只能移动left,
* left = 0 时 11 >= 6 更新result
* left = 1 时 9 >= 6 更新result
* left = 2 时 6 >= 6 更新result
* left = 3时 0 <6 结束while
*
* result 保存的是这一次滑动窗口的最小长度
*
* 代码中为什么使用Integer.MAX_VALUE?
* 给出的数据个数可能很多,但是你不能初始化result为任何一个具体的数字,
* 此时使用Integer的最大值来初始化,如果整个过程不包含满足条件的 result就不会变化(还是Integer的最大值)
* 一旦有满足条件的字串,result就会改变
*
* 为什么使用 Math.min(result, right - left + 1)?
*目的是为了更新result
* 举个例子:第一个字串最小result是1
* 第二个字串最小result是2
* 这个时候就要保留第一次最小的result
* (我认为只要找到了result == 1 就不需要去执行后面的步骤了,可以直接返回)
*
*/
package com.leetcode.array;
/**
* 209.长度最小的子数组
* 给定一个含有 n 个正整数的数组和一个正整数 s ,
* 找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。
* 如果不存在符合条件的子数组,返回 0。
*
* 示例:
*
* 输入:s = 7, nums = [2,3,1,2,4,3] 输出:2
* 解释:子数组 [4,3] 是该条件下的长度最小的子数组
*/
public class FindMiniSubarray {
public static void main(String[] args) {
int[] nums = {2,3,1,2,4,3};
int s = 10;
// int miniLen = FindSubarray(nums, s);
int miniLen = miniSubarray(nums, s);
System.out.println(miniLen);
}
/**
* 自己的第一次的原始想法
* 1.双指针。first 控制开始,second控制结束,
* 步长0 - length - 1,依次寻找
* 时间复杂度O(n^2)
*/
// public static int FindSubarray(int[] nums, int s){
// for (int i = 0; i < nums.length - 1; i++) {
// int first = 0;
// if(i == 0){
// for (int j = 0; j < nums.length; j++) {
// if(nums[i] >= s) return i + 1;
// }
// }
// else {
// for (int second = first + i; second < nums.length; second++) {
// int sum = 0;
// for (int j = first; j <= second; j++) {
// sum += nums[j];
// }
// if(sum >= s) return i + 1;
// first++;
// }
// }
// }
// return 0;
// }
/**
* 滑动窗口法(确定一个满足条件的子数组,从头开始依次减少,求出满足条件的最小长度)
* for 循环控制right的位置(left到right为一个满足条件的子数组,在子数组中找出满足条件的最小长度)
* 例如:nums :1,2, 3, 6, 7 ; s = 6
* left = 0; right = 3;时满足条件,但是其实单一个6就满足了,所以此时需要在这个子数组中找满足条件的最小长度
* 步骤:right = 3,是确定了的,此时只能移动left,
* left = 0 时 11 >= 6 更新result
* left = 1 时 9 >= 6 更新result
* left = 2 时 6 >= 6 更新result
* left = 3时 0 <6 结束while
*
* result 保存的是这一次滑动窗口的最小长度
*
* 代码中为什么使用Integer.MAX_VALUE?
* 给出的数据个数可能很多,但是你不能初始化result为任何一个具体的数字,
* 此时使用Integer的最大值来初始化,如果整个过程不包含满足条件的 result就不会变化(还是Integer的最大值)
* 一旦有满足条件的字串,result就会改变
*
* 为什么使用 Math.min(result, right - left + 1)?
*目的是为了更新result
* 举个例子:第一个字串最小result是1
* 第二个字串最小result是2
* 这个时候就要保留第一次最小的result
* (我认为只要找到了result == 1 就不需要去执行后面的步骤了,可以直接返回)
*
*/
public static int miniSubarray(int[] nums, int s) {
int sum = 0;
int left = 0;
int result = Integer.MAX_VALUE;
for (int right = 0; right < nums.length; right++) {
sum += nums[right];
while (sum >= s){
result = Math.min(result, right - left + 1);
sum -= nums[left++];
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
}