leetcode打卡1.1

一道刷了两三遍的滑动窗口题:第一遍没了解思路,第二遍看过灵神题解并结合AI而尝试,第三遍独立写出该题并于2025年5月18日写下该篇博客进行记录,以勉励以后的计算机练习

感谢一切帮助我的人和物,感谢自己,感谢这个世界 

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

 

如上图所示:

我们需要找到一个最小的连续子数组来满足题目条件,该子数组中的元素总和应大于等于target,我的第一篇尝试,虽然我也不太记得自己是用什么思路想的了,不过按照现在的思路看之前写的题,只感到稚嫩和不熟练

        //分块
        /*
        比较块,比较答案和最小值
        窗口块,快慢指针窗口滑动
        */
        int slow=0;
        int ans=INT_MAX;
        int sum=0;
        for(int fast=0;fast<nums.size();fast++)
        {           
            sum+=nums[fast]; 
            while(sum>=target)//慢指针窗口
            {
                int len=fast-slow+1;
                ans=min(ans,len);
                sum-=nums[slow];
                slow++;
            }
           
        }
        if(slow==0) return 0;
        return ans;

这篇应该是看题解过的,因为我没什么印象了(雾) 

这篇AC代码和第三篇类似,我讲解第三篇时再好好谈谈

第二篇

         int n=nums.size();
         int ans=0;
         int left=0;
         int sum=0;

         for(int i=0;i<n;i++) sum+=nums[i];//求出总和

         for(int right=0;right<n;right++)//循环
         {
             sum-=nums[right];//总和相减
             while(sum<target)
             {
                 sum+=nums[left];//相加,直到总和大于等于target
                 left++;//左指针右移
             }
             ans=min(ans,right-left+1);
         }
         return ans;

这份代码中我采用了逆向思维进行查询,我们先将所有值相加得到sum,然后,很愚蠢的一件事情发生了,我居然没注意如果sum小于target怎么办,也就是说,如果sum小于target,那么直接返回0即可,但我疏忽了这一点。

好,假设有数据点sum>=target,进行以下操作

其次,我在right的遍历过程中,我是这样思考的,每轮遍历就将sum减nums[right],

如果相减之后的值仍然大于等于target,那么我就将最小进行记录,

如果相减之后的值小于target,那么我就将它放入循环用left进行相加,

这题的原意已经被我完全混淆,因为如果从right开始相减,那不就等同于左边界是right而右边界是nums.size()吗,这样求出来的结果怎么可能正确!

不用看了,题目理解错误,还想妄图逆向思维进行计算,不错才怪

第三

        int n=nums.size();
        int ans=1e9+5;
        int left=0;
        int sum=0;
        int res=0;
        for(int i=0;i<nums.size();i++) res+=nums[i];
        if(res<target) return 0;

        for(int right=0;right<nums.size();right++)
        {
            sum+=nums[right];
            while(sum>=target)
            {
                ans=min(ans,right-left+1);
                sum-=nums[left];
                left++;
            }
        }
        return ans;

第三篇AC代码和第一篇很像,看完这篇之后可以和第一篇对照一下

第三篇代码:

 第一,这次我们注意到了如果所有数得到的和res小于target是一个不符合题意的解,那么这个就需要直接退出返回0

第二,我们这次的滑动窗口right从0开始,然后向右滑动,依次相加,如果得到的sum值大于等于target,那么我们就要进入循环将窗口缩小,直到sum小于0,并且,我们的循环中要注意计算答案,不能放在外循环中,那里得到的窗口都是sum<target的

以下是我在闲余时写的笔记

        // //分块
        // /*
        // 比较块,比较答案和最小值
        // 窗口块,快慢指针窗口滑动
        // */
        // int slow=0;
        // int ans=INT_MAX;
        // int sum=0;
        // for(int fast=0;fast<nums.size();fast++)
        // {           
        //     sum+=nums[fast]; 
        //     while(sum>=target)//慢指针窗口
        //     {
        //         int len=fast-slow+1;
        //         ans=min(ans,len);
        //         sum-=nums[slow];
        //         slow++;
        //     }
           
        // }
        // if(slow==0) return 0;
        // return ans;
第一份答题题解

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n = nums.size();
        int ans = INT_MAX; // 初始化为最大值
        int left = 0;      // 左指针
        int sum = 0;       // 当前窗口的和

        for (int right = 0; right < n; right++) { // 右指针
            sum += nums[right]; // 将右指针的值加入当前窗口的和

            // 当当前窗口的和大于等于目标值时,尝试缩小窗口
            while (sum >= target) {
                ans = min(ans, right - left + 1); // 更新最小长度
                sum -= nums[left]; // 移除左指针的值
                left++; // 左指针右移
            }
        }

        // 如果没有找到满足条件的子数组,返回 0
        return (ans == INT_MAX) ? 0 : ans;
    }
};
	//正统答案
	
	思路确实存在逻辑上的问题,这也是导致代码无法正确运行的主要原因。在滑动窗口问题中,我们需要通过动态调整窗口的大小来找到满足条件的最小窗口,而不是通过扩大窗口来寻找满足条件的窗口。以下是对你思路的详细分析和解释:

### 问题分析
1. **窗口扩大的逻辑问题**:
   - 你的代码中,当 `sum < target` 时,你试图通过增加 `left` 来调整窗口大小,这与滑动窗口的常规逻辑完全相反。
   - 在滑动窗口问题中,当当前窗口的和小于目标值时,应该通过增加 `right` 指针来扩大窗口,而不是减少 `left`。

2. **窗口缩小的逻辑问题**:
   - 当窗口的和大于等于目标值时,应该通过增加 `left` 指针来缩小窗口,以寻找更小的满足条件的窗口。
   - 你的代码中没有正确实现这一点。

3. **变量 `sum` 的使用问题**:
   - 你在代码中将 `sum` 初始化为整个数组的总和,这在逻辑上是错误的。`sum` 应该是当前窗口的和,而不是整个数组的总和。

### 修正思路
为了实现滑动窗口的正确逻辑,我们需要:
1. **初始化窗口**:从左到右逐步扩大窗口,直到窗口的和大于等于目标值。
2. **调整窗口**:当窗口的和大于等于目标值时,尝试通过增加 `left` 指针来缩小窗口,同时更新最小窗口长度。
3. **重复步骤**:继续扩大窗口(增加 `right` 指针),重复上述过程,直到遍历完整个数组。

### 修正后的代码
以下是修正后的代码,使用滑动窗口的正确逻辑:

```cpp
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n = nums.size();
        int ans = INT_MAX; // 初始化为最大值
        int left = 0;      // 左指针
        int sum = 0;       // 当前窗口的和

        for (int right = 0; right < n; right++) { // 右指针
            sum += nums[right]; // 将右指针的值加入当前窗口的和

            // 当当前窗口的和大于等于目标值时,尝试缩小窗口
            while (sum >= target) {
                ans = min(ans, right - left + 1); // 更新最小长度
                sum -= nums[left]; // 移除左指针的值
                left++; // 左指针右移
            }
        }

        // 如果没有找到满足条件的子数组,返回 0
        return (ans == INT_MAX) ? 0 : ans;
    }
};
```

### 修正后的代码说明
1. **初始化 `ans` 为 `INT_MAX`**:
   - 这样可以确保在第一次更新时能够正确记录最小长度。

2. **滑动窗口逻辑**:
   - 使用两个指针 `left` 和 `right` 来表示窗口的左右边界。
   - 在每次循环中,将 `right` 指针的值加入当前窗口的和。
   - 如果当前窗口的和大于等于目标值 `target`,则尝试通过右移 `left` 指针来缩小窗口,并更新最小长度 `ans`。

3. **返回值**:
   - 如果最终 `ans` 仍为 `INT_MAX`,说明没有找到满足条件的子数组,返回 `0`。

### 示例
假设输入:
```cpp
target = 7
nums = {2, 3, 1, 2, 4, 3}
```

运行修正后的代码,输出:
```
2
```

解释:最小长度的子数组是 `[4, 3]`,长度为 2。

### 总结
你的思路中确实存在逻辑问题,主要是在窗口的扩大和缩小操作上。滑动窗口的核心思想是:
1. **扩大窗口**:通过增加 `right` 指针来扩大窗口,直到窗口的和大于等于目标值。
2. **缩小窗口**:当窗口的和大于等于目标值时,通过增加 `left` 指针来缩小窗口,同时记录最小窗口长度。
	
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n=nums.size();
        int ans=1e9+5;
        int left=0;
        int sum=0;
        int res=0;
        for(int i=0;i<nums.size();i++) res+=nums[i];
        if(res<target) return 0;

        for(int right=0;right<nums.size();right++)
        {
            sum+=nums[right];
            while(sum>=target)
            {
                ans=min(ans,right-left+1);
                sum-=nums[left];
                left++;
            }
        }
        return ans;
    }
};
	二刷题解

当然,我没有忘记后面的进阶思考,如果它这样提问,那么我就将在不久后尽量将其写出

2025/5/18

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值