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;
posted @ 2024-08-01 14:01  Neking  阅读(81)  评论(0编辑  收藏  举报