数组:存放在连续内存空间上的相同类型数据的集合
- 下标从0开始
- 内存地址是连续的
一.长度最小的数组
LeetCode题目链接:209. 长度最小的子数组
暴力法
- 思路:采用暴力解法可以直接求得每个满足条件的子数组,并进行比较拿到长度最小的数组,故需要遍历数组的每个元素作为每个子数组的起始元素,然后往后求和直到>=目标值即可停止,因为往后没有必要了我们需要的是长度最短的子数组。另外值得一提都是为了避免不必要的循环,另加了个终止判断:当J走到数组最后一个元素时,也并没有满足子数组之和>=目标值,说明子数组起始元素i已经没有往后移动的必要了,就可以直接返回结果。
- 代码实现
public static int minSubArrayLen(int target, int[] nums) {
int min = Integer.MAX_VALUE;
for (int i = 0; i < nums.length; i++) {
int j = i;
int sum = 0;
while (j < nums.length) {
sum += nums[j++];
if (sum >= target) {
if (min > (j - i)) {
min = j - i;
}
break;
}
// 优化:避免不必要的循环,避免超时问题
if(j == nums.length || min == 1){
return min == Integer.MAX_VALUE ? 0 : min;
}
}
}
return min == Integer.MAX_VALUE ? 0 : min;
}
-
复杂度分析
时间复杂度:O(n^2)
空间复杂度:O(1)
滑动窗口(双指针)
-
思路:滑动窗口是一种基于双指针的一种思想,两个指针指向的元素之间形成一个窗口。
分类:窗口有两类,一种是固定大小类的窗口,一类是大小动态变化的窗口。
该题则用的是大小动态变化的窗口。可什么要使用该思想呢,还要回到题目上来,暴力破解是遍历元素作为子数组的起始位置,而是否可以遍历元素作为子数组的终止位置呢,循环内已然是求该元素之前子数组的元素之和sum,当sum>=target时,则该元素为终止位置的子数组可满足条件,但是请注意该子数组是最小的数组嘛,就需要将起始位置向前移动来判断是否依然满足条件sum>=target,当不满足时则继续移动终止位置。
-
代码实现
public static int minSubArrayLen2(int target, int[] nums) {
int left = 0, right = 0, min = Integer.MAX_VALUE, sum = 0;
while(right < nums.length){
sum += nums[right];
while (sum >= target) {
min = Math.min(min, right - left + 1);
sum -= nums[left];
left++;
}
right++;
}
return min == Integer.MAX_VALUE ? 0 :min;
}
- 时间复杂度:O(n)
- 空间复杂度:O(1)