首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【优选算法必刷100题】第009~010题(滑动窗口):长度最小的子数串、无重复字符的最长字串

【优选算法必刷100题】第009~010题(滑动窗口):长度最小的子数串、无重复字符的最长字串

作者头像
用户11915063
发布2025-11-20 13:05:05
发布2025-11-20 13:05:05
440
举报

09.长度最小的子数串

题目链接:

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

题目描述:

题目示例:

解法一:(暴力求解)(会超时)
算法思路:

【从前往后】枚举数组中的任意一个元素,把它当成起始位置。然后从这个【起始位置】开始,然后寻找一段最短的区间,使得这段区间的和【大于等于】目标值。

将所有元素作为起始位置所得的结果中,找到【最小值】即可。

--代码这里就不演示了

解法二:(滑动窗口)
算法思路:

由于此问题分析的对象是【一段连续的区间】,因此可以考虑【滑动窗口】的思想来解决这道题

让滑动窗口满足:从 i 位置开始,窗口内所有的和小于 target (那么当窗口内元素之和第一次大于等于目标值的时候,就是 i 位置开始,满足条件的最小长度)

做法:将右端元素划入窗口之中,统计出此时窗口内元素的和:

  • 如果窗口内元素之和大于 target :更新结果,并且将左端元素划出去的同时继续判断是否满足条件并更新结果(因为左端元素可能很小,划出去之后依旧满足条件)
  • 如果窗口内元素之和不满足条件:right++,另下一个元素进入窗口

为何滑动窗口可以解决问题,并且时间复杂度更低?

这个窗口寻找的是:以当前窗口最左侧元素(记为 left)为基准,符合条件的情况。也就是在这道题中,从 left 开始,满足区间和 sum>=target 时的最右侧(记为 right)能到哪里

我们既然已经找到从 left 开始的最优的区间,那么就可以大胆舍去 left。但是如果继续像方法一一样,重新开始统计第二个元素(left2)往后的和,势必会有大量重复的计算(因为我们在求第一段区间的时候,已经算出很多元素的和了,这些和是可以在计算下次区间和的时候用上的)

此时,right1的作用就体现出来了,我们只需要将 left1 这个值从 sum 中剔除。从 right1 这个元素开始,往后找满足 left2 元素的区间 (此时 right1 也有可能是满足的,因为 left1 可能很小。sum 剔除掉 left1 之后,依旧满足大于等于 target )。这样我们就能省掉大量重复的计算

  • 这样我们不仅能解决问题,效率也会大大提升。

时间复杂度:虽然代码是两层循环,但是我们的 left 指针和 right 指针都是不回退的,两者最多都往后移动 n 次。因此时间复杂度是 O(N)

C++代码演示:
代码语言:javascript
复制
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) 
    {
        int n=nums.size(),sum=0,len=INT_MAX;
        for(int left=0,right=0;right<n;right++)
        {
            sum+=nums[right];//进窗口
            while(sum>=target)//判断
            {
                len=min(len,right-left+1);//更新
                sum-=nums[left++];
            }
        }    
        return len==INT_MAX?0:len;
    }
};
算法总结&&笔记展示:

博主笔记(字迹有点丑,请大家见谅):


10.无重复字符的最长字串

题目链接:

3. 无重复字符的最长子串 - 力扣(LeetCode)

题目描述:

题目示例:

解法一:(暴力求解)(不会超时,可以通过):
算法思路:

枚举【从每一个位置】开始往后,无重复字符的子串可以到达什么位置。找到其中长度最大的即可。

在往后寻找无重复子串能到达的位置时,可以利用【哈希表】统计出字符出现的频次,来判断什么时候子串出现了重复元素

解法二:(滑动窗口)
算法思路:

研究的对象依旧是一段连续的区间,因此继续使用【滑动窗口】思想来优化。

让滑动窗口满足:窗口内所有元素都是不重复的

做法:右端元素 ch 进入窗口的时候,哈希表统计这个字符的频次:

  • 如果这个字符出现的频次超过 1 ,说明窗口内有重复元素,那么就从左侧开始划出窗口,直到 ch 这个元素的频次变为 1,然后再更新结果
  • 如果没有超过 1,说明当前窗口没有重复元素,可以直接更新结果
C++代码演示:
代码语言:javascript
复制
class Solution {
public:
    int lengthOfLongestSubstring(string s) 
    {
        int hash[128]={0};
        int n=s.size(),left=0,right=0,ret=0;
        while(right<n)
        {
            hash[s[right]]++;
            while(hash[s[right]]>1)
            {
                hash[s[left++]]--;
            }
            ret=max(ret,right-left+1);
            right++;
        }
        return ret;
    }
};
算法总结&&笔记展示:

博主笔记(字迹有点丑,请大家见谅):


往期回顾:

【优选算法必刷100题】第001~002题(双指针算法):移动零、复写零问题

【优选算法必刷100题】第003~004题(双指针算法):快乐数和盛水最多的容器

【优选算法必刷100题】第005~006题(双指针算法):有效三角形的个数和查找总价值为目标值的两个商品

【优选算法必刷100题】第007~008题(双指针算法):三数之和,四数之和

总结:本篇博客介绍了两个滑动窗口算法实战题解:209.长度最小的子数组和3.无重复字符的最长子串。针对第一题,通过暴力解法和滑动窗口对比,详细解释了滑动窗口的高效原理,即通过左右指针不回退降低时间复杂度。第二题同样采用滑动窗口,利用哈希表统计字符频次来检测重复。如果文章对你有帮助的话,欢迎评论,点赞,收藏加关注,感谢大家的支持

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-11-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 09.长度最小的子数串
    • 解法一:(暴力求解)(会超时)
      • 算法思路:
    • 解法二:(滑动窗口)
      • 算法思路:
    • C++代码演示:
      • 算法总结&&笔记展示:
  • 10.无重复字符的最长字串
    • 解法一:(暴力求解)(不会超时,可以通过):
      • 算法思路:
    • 解法二:(滑动窗口)
      • 算法思路:
    • C++代码演示:
      • 算法总结&&笔记展示:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档