LeetCode | 209 MinimumSizeSubarraySum
分析
本题中是找与target相符的最小连续的子数组和————能够容纳target这么大的最小子区间。虽然本节引入了滑动窗口的概念,可我更偏好于,这是一只毛毛虫在数组上的移动,找到最小的容纳自己位置的地方(只有全部遍历过,才能知晓最小)
- target可看作毛虫本身的重量,数组中的每个元素值表示可承受的重量,right右指针看做毛虫的头,left左指针看做毛虫的尾巴
- 在头部前进的过程中,扫过的连续元素累积和如果大于等于毛虫自身的重量,尾部便可以开始收缩前进,这时如果毛虫占据的数组空间无法承载毛虫的重量,毛虫的头部就要继续前进
- 所以,两个循环,外部循环控制的是头部的移动,内部循环控制的是尾部的移动,内外循环其实只是毛虫在数组区间上的一次遍历
- 在内循环中记录下遍历的最小子区间边界索引和最小长度
本节的核心其实还是在于遍历,双层for循环这种暴力破解确实可以做,主要还是所给出的target,且题意表示的子区间是局部连续性,给了我们一个更加明确的问题条件,用"滑动窗口/毛虫移动"解法就更优
主类
package com.github.dolphinmind.array;
/**
* @author dolphinmind
* @ClassName MinimumSizeSubarraySum
* @description 209 长度最小的子数组
* @date 2024/8/1
*/
public class MinimumSizeSubarraySum {
/**
* 毛毛虫移动的步伐,右指针是头,左指针是尾,循环结束双指针的目的就是遍历,内循环中获取最小子数组和的长度
* 如何获取这个数组区间呢?
* 在内循环中,如果sum大于等于target,则说明找到了一个满足题意的区间,此时需要更新result,同时更新区间的左右指针,
* 通过比较最小子数组的大小,来给minIndex和maxIndex赋值,即确定了最小子区间
* @param nums
* @param target
* @return
*/
public int caterpillarMovement(int[] nums, int target) {
if (nums.length == 0) {
return -1;
}
int left = 0;
int right = 0;
int sum = 0;
int result = Integer.MAX_VALUE;
int minIndex = 0;
int maxIndex = 0;
/**
* 外循环控制滑动窗口的右指针
*/
while (right < nums.length) {
sum += nums[right];
/**
* 内循环控制滑动窗口的左指针,target就像是毛毛虫本身的分量
*/
while (sum >= target) {
int len = right - left + 1;
if (len < result) {
result = len;
minIndex = left;
maxIndex = right;
}
sum -= nums[left++];
}
// 右指针放在此处自增,其实是为了整个流程规范,
// 不管内循环是否执行,right指针始终要进行自增,即便进入了内循环,看做移动滞后即可
right++;
}
printMinLenArray(nums, minIndex, maxIndex);
return result == Integer.MAX_VALUE ? 0 : result;
}
/**
* 打印最短子数组
* @param nums
* @param left
* @param right
*/
public void printMinLenArray(int[] nums, int left, int right) {
System.out.print("[");
while (left <= right) {
System.out.print(nums[left++] + " ");
}
System.out.println("]");
}
}
测试类
package com.github.dolphinmind.array;
import org.junit.Test;
/**
* @author dolphinmind
* @ClassName MinimumSizeSubarraySumTest
* @description
* @date 2024/8/1
*/
public class MinimumSizeSubarraySumTest {
@Test
public void test_caterpillarMovement() {
// int[] nums = {2,3,1,2,4,3};
// int[] nums = {};
int[] nums = {1};
int target = 7;
MinimumSizeSubarraySum minimumSizeSubarraySum = new MinimumSizeSubarraySum();
int res = minimumSizeSubarraySum.caterpillarMovement(nums, target);
System.out.println("'毛虫移动/滑动窗口'获取最小和区间长度:" + res);
}
}
解释
result初始值为什么控制这么大?
在滑动窗口算法中,将result的初始值设置为Integer.MAX_VALUE
原因为了确保在算法执行过程中能够正确地更新result为找到的最小值
- 避免初始值影响结果:如果初始值设置太小,可能会干扰算法找到真正的最小值
- 确保正确更新:任何合法的数组长度都小于Integer.MAX_VALUE,算法在第一次找到符合条件的子数组时,无论这个子数组的长度是多少,都会更新result的长度
- 处理无解情况:如果数组中没有任何子数组的和能够达到或超过target,
return result == Integer.MAX_VALUE ? 0 : result;