小哆啦解题记:长度最小的子数组

109 阅读4分钟

小哆啦解题记:长度最小的子数组

小哆啦开始刷力扣的第二十五天

209. 长度最小的子数组 - 力扣(LeetCode)

难题降临

在算法的神秘森林里,住着爱挑战的小哆啦。这天,他遇到了一道棘手的关卡 ——“长度最小的子数组”。题目要求是,给定一个包含 n 个正整数的数组和一个正整数 target,要找出数组里总和大于等于 target 的最短子数组的长度,要是不存在这样的子数组,就返回 0。小哆啦眼睛放光,心想:“这能难倒我?看我的!”

暴力出击

小哆啦采用了简单粗暴的暴力解题法。他打算遍历数组中所有可能的子数组,计算每个子数组的和,找出满足和大于等于 target 的最短子数组长度。于是小哆啦写下了如下代码:

function minSubArrayLen(target: number, nums: number[]): number {
    let minLength = Infinity;
    const n = nums.length;

    // 遍历所有可能的子数组起始位置
    for (let i = 0; i < n; i++) {
        let sum = 0;
        // 遍历以 i 为起始位置的所有子数组
        for (let j = i; j < n; j++) {
            sum += nums[j];
            if (sum >= target) {
                // 更新最小长度
                minLength = Math.min(minLength, j - i + 1);
                // 由于要找最短的,后续更长的子数组无需再考虑
                break;
            }
        }
    }

    return minLength === Infinity ? 0 : minLength;
}

小哆啦按照这个思路,就像一个不知疲倦的小矿工,从数组的第一个元素开始,逐个检查所有可能的子数组。把每个子数组的元素加起来,看看和是否能达到或超过 target。要是满足条件,就赶紧记录下这个子数组的长度,然后接着去试下一个。小哆啦忙得晕头转向,一会儿挠挠脑袋,一会儿写写画画,嘴里还不停地嘟囔着计算结果。

小智点拨

就在小哆啦忙得不可开交的时候,聪明的小智溜达了过来。小智看着小哆啦忙乱的样子,忍不住笑着说:“小哆啦,你这样一个一个试,要是数组里的数字超级多,那不得算到猴年马月呀!” 小哆啦一听,停下手中的笔,疑惑地看着小智:“那还有啥更好的办法吗?”

小智神秘一笑,说:“试试滑动窗口的办法吧。就像有一个会滑动的小窗口在数组上移动,根据窗口内元素的和来调整窗口的大小。” 小哆啦眼睛一亮,觉得这办法听起来挺厉害,赶紧按照小智说的思路开始写代码:

function minSubArrayLen(target: number, nums: number[]): number {
    let left = 0;
    let sum = 0;
    let minLength = nums.length + 1; 

    for (let right = 0; right < nums.length; right++) {
        sum += nums[right];
        while (sum >= target) {
            minLength = minLength > (right - left + 1) ? right - left + 1 : minLength;
            sum -= nums[left];
            left++;
        }
    }

    return minLength === nums.length + 1 ? 0 : minLength;
}

初尝挫折

小哆啦兴奋地运行代码,结果却发现有些测试用例没有通过。他皱着眉头,像个小侦探一样仔细检查代码。小智在一旁鼓励他:“别着急,再看看哪里出了问题。滑动窗口的关键就是要合理调整左右指针的位置。”

修正凯旋

小哆啦静下心来,重新梳理思路。他发现原来是在更新 minLength 和移动指针的时候,逻辑出现了一点小偏差。经过一番修改,他终于得到了正确的代码:

function minSubArrayLen(target: number, nums: number[]): number {
    let left = 0;
    let sum = 0;
    // 初始化为无穷大,方便后续比较更新
    let minLength = Infinity; 

    for (let right = 0; right < nums.length; right++) {
        sum += nums[right];
        while (sum >= target) {
            minLength = Math.min(minLength, right - left + 1);
            sum -= nums[left];
            left++;
        }
    }

    return minLength === Infinity ? 0 : minLength;
}

这一次,代码顺利通过了所有测试用例。小哆啦高兴得跳了起来,抱着小智说:“谢谢你,小智!滑动窗口的办法太神奇了!”

结语

经过这次与 “长度最小的子数组” 的激烈交锋,小哆啦不仅成功通关,更收获了宝贵的经验和成长。在算法这片充满奇幻与挑战的森林中,每一道难题都是一座等待攀登的高峰,每一次失败都是积累智慧的宝藏。

小哆啦深刻体会到,解题就像一场冒险,有时候勇往直前的蛮劲并不能带你穿越迷雾,而巧妙的策略和灵活的思维才是开启胜利之门的钥匙。同时,朋友的陪伴与帮助就如同夜空中的繁星,在迷茫时为你指引方向。

未来,算法森林里还会有更多未知的难题等待着小哆啦。但他不再害怕,因为他知道,只要保持好奇心和求知欲,不断学习新的方法和技巧,并且珍惜身边朋友的支持,他就能在这片奇妙的世界里越走越远,攻克一个又一个看似不可能的挑战,书写属于自己的辉煌解题传奇!