爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      算法魅力-双指针之滑动窗口的叛逆

      首页 知识中心 软件开发 文章详情页

      算法魅力-双指针之滑动窗口的叛逆

      2025-02-12 09:12:00 阅读次数:12

      元素,哈希,指针,数组,窗口

      1.滑动窗口的定义

       滑动窗口是一种双指针算法的特例,主要用于处理连续区间的问题,特别是在字符串或数组上寻找满足某些条件的连续子区间。在滑动窗口中,通常有两个指针,分别称为“窗口的起始指针”和“窗口的结束指针”,它们一起构成一个“窗口”,在数组或字符串上移动。

      滑动窗口的几个关键特点
      1.动态调整大小:窗口的大小和位置会根据问题的需求动态地调整。
      2.连续性:窗口内的元素是连续的。
      3.方向性:窗口通常从数组的左端开始,向右移动。

      滑动窗口算法的步骤
      - 初始化两个指针,通常称为`left`和`right`,它们分别表示窗口的起始和结束位置。
      - 移动`right`指针来扩展窗口,直到窗口中的元素满足某个条件。
      - 当窗口满足条件后,尝试通过移动`left`指针来缩小窗口,同时保持窗口中的元素满足条件。
      - 在移动指针的过程中,更新所需的答案(例如最大或最小长度)。

      简而言之,可以理解成两个指针的同向移动。

      滑动窗口算法常用于以下典型问题:
      - 最长不含重复字符的子字符串:在字符串中找到一个最长子串,该子串不包含任何重复字符。
      - 最小覆盖子串:在字符串S中找到一个包含字符串T中所有字符的最短连续子串。

      2.算法实战

      2.1 长度最小的子数组

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

      算法魅力-双指针之滑动窗口的叛逆

      算法思路

      1.暴力枚举(超时)

      从前往后枚举数组中的任意一个元素,把它当成起始位置。然后从这个起始位置开始,然
      后寻找一段最短的区间,使得这段区间的和「大于等于」目标值。
      将所有元素作为起始位置所得的结果中,找到最短的数组即可。

       

      class Solution {
      public:
       int minSubArrayLen(int target, vector<int>& nums) {
       // 记录结果
       int ret = INT_MAX;
       int n = nums.size();
       
       // 枚举开始位置
       for (int start = 0; start < n; start++)
       {
       int sum = 0; // 记录从这个位置开始的连续数组的和
       // 寻找结束位置
       for (int end = start; end < n; end++)
       {
       sum += nums[end]; // 将当前位置加上
       
       if (sum >= target) // 当这段区间内的和满⾜条件时
       {
       // 更新结果,start 开头的最短区间已经找到
       ret = min(ret, end - start + 1);
       break;
       }
       }
       }
       // 返回最后结果
       return ret == INT_MAX ? 0 : ret;
       }
      };

      补充:将ret赋值无穷大,即=INT_MAX

      2.滑动窗口解法

      让滑动窗口满足:从 i 位置开始,窗口内所有元素的和小于 target (当窗口内元素之和
      第一次大于等于目标值的时候,就是 i 位置开始,满足条件的最小长度)。
       
      做法:将右端元素划入窗口中,统计出此时窗口内元素的和,如果窗口内元素之和大于等于 target, 更新结果,并且将左端元素划出去的同时继续判 断是否满足条件并更新结果(因为左端元素可能很小,划出去之后依旧满足条件)
      如果窗口内元素之和不满足条件: right++ ,另下一个元素进入窗口。
      那么为何滑动窗口可以解决问题,并且时间复杂度更低?
       
      这个窗口寻找的是:以当前窗口最左侧元素(记为 left1 )为基准,符合条件的情况。也
      就是在这道题中,从 left1 开始,满足区间和 sum >= target 时的最右侧(记为
      right1 )能到哪里。
       
      既然已经找到从 left1 开始的最优的区间,那么就可以舍去 left1 。但是如果继续像方法一一样,重新开始统计第二个元素( left2 )往后的和,势必会有大量重复的计算(因为在求第一段区间的时候,已经算出很多元素的和了,这些和是可以在计算下次区间和的时候用上的)。
       
      此时, rigth1 的作用就体现出来了,我们只需将 left1 这个值从 sum 中剔除。从right1 这个元素开始,往后找满足 left2 元素的区间(此时 right1 也有可能是满足的,因为 left1 可能很小。 sum 剔除掉 left1 之后,依旧满足大于等于target )。这样我们就能省掉大量重复的计算。
       
       
      时间复杂度:虽然代码是两层循环,但是我们的 left 指针和 right 指针都是不回退的,两者
      最多都往后移动 n 次。因此时间复杂度是O(n).

       

      class Solution {
      public:
          int minSubArrayLen(int target, vector<int>& nums) {
            //sort(nums.begin(),nums.end());
              int len=INT_MAX,n=nums.size();
              int sum=0;
             // int left=0;
              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;
          }
      };

      2.2 无重复字符的最长子串

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

      算法魅力-双指针之滑动窗口的叛逆

      算法思路

      1.暴力枚举

      首先在暴力枚举的过程中,可以通过哈希表来记录字符出现的次数,简单来说,就是定义一个数组,每个字符对应的ASCII值是数组的相应位置。

      class Solution {
      public:
          int lengthOfLongestSubstring(string s) {
              int n=s.size(),ret=0,i,j;
              for( i=0;i<n;i++){
                  int hash[128]={0};
                  for( j=i;j<n;j++){
                      hash[s[j]]++;
                     if(hash[s[j]]>1)
                      break;
                  }
                  ret=max(ret,j-i);
              }
              return ret;
          }    
      };

      当字符字数大于一的时候,就跳出内循环,更新结果,更改数组首元素。

      2.滑动窗口

      在暴力枚举的过程中,我们发现当进行新的一层外循环时,只要还在遇到重复字母的范围内,就会重复遍历相同的子串子集,并且长度是减小的。

      所以我们可以省略这些操作,让滑动窗口满足:窗口内所有元素都是不重复的。

      做法:右端元素 ch 进入窗口的时候,哈希表统计这个字符的频次:
       
      如果这个字符出现的频次超过 1 ,说明窗口内有重复元素,那么就从左侧开始划出窗口, 直到 ch 这个元素的频次变为 1 ,然后再更新结果。
       
      如果没有超过 1 ,说明当前窗口没有重复元素,可以直接更新结果
       
       
      class Solution {
      public:
          int lengthOfLongestSubstring(string s) {
              int n=s.size();
              int left=0,right=0,ret=0;
              int hash[128]={0};
              while(right<n){
                  hash[s[right]]++;//进入窗口
                  while(hash[s[right]]>1){//判断
                      hash[s[left]]--;
                      left++;}//出窗口
                      //ret=max(ret,(right-1)-(left-1)+1);
                      ret=max(ret,right-left+1);//更新结果
                  right++;//下一个元素进入窗口
              }
              return ret;
          }
      };

      2.3 最大连续 1 的个数 III

      1004. 最大连续1的个数 III - 力扣(LeetCode)

      算法魅力-双指针之滑动窗口的叛逆

      算法思路

      1.暴力枚举(超时)

      用两个循环嵌套,固定首数组元素,然后遍历,枚举出所有情况。定义一个count来储存0的数量。

      class Solution {
      public:
          int longestOnes(vector<int>& nums, int k) {
             int n=nums.size();
             int i,j,len=0;
             for(i=0;i<n;i++){
              int count=0;
              for(j=i;j<n;j++){
                  if(nums[j]==0)
                  count++;
                  if(count>k){
                     break;
                  }
                  len=max(len,j-i+1);
              }
             }
             return len;
          }
      };

      2.滑动窗口

      可以把问题转化成:求数组中一段最长的连续区间,要求这段区间内 0 的个数不超过 k 个。 既然是连续区间,可以考虑使用「滑动窗口」来解决问题。
       
      class Solution {
      public:
          int longestOnes(vector<int>& nums, int k) {
              int len=0,zero=0;
              for(int left=0,right=0;right<nums.size();right++){
                  if(nums[right]==0) zero++;
                  while(zero>k){
                      if(nums[left++]==0){
                          zero--;
                      }
                  }
                  len=max(len,right-left+1);
              }
              return len;
          }
      };

      算法采用双指针技术来维护一个窗口,该窗口包含最多 k个0。通过调整窗口的左右边界,我们可以找到包含最多1的子数组。
      算法步骤
      1. 初始化变量:
         - len:记录当前找到的最长子数组的长度。
         - zero:记录当前窗口中0的数量。
         - left和 right:分别表示滑动窗口的左右边界。
      2. 遍历数组:
         - 使用 right指针遍历数组 nums。
         - 如果 `nums[right]` 是0,则增加 zero计数。
      3. 调整窗口大小:
         - 当 zero的数量超过 k 时,表示窗口中的0太多,需要通过增加 left 指针来缩小窗口,直到窗口中的0的数量不大于 k。
         - 在增加 left指针的过程中,如果 nums[left] 是0,则减少 zero计数。
      4. **更新最长子数组长度**:
         - 在每次调整窗口后,计算当前窗口的长度(`right - left + 1`),并与 len比较,更新 len为最大值。
      5. 返回结果:
         - 遍历完成后,返回 len 作为结果,它表示最长的连续1的子数组的长度,同时允许最多 k 个0。
       

      哈希表的简要补充

      哈希表(Hash table),也被称作散列表,是一种数据结构,用于存储键值对,并能够实现快速查找。哈希表通过一个哈希函数来计算每个键的哈希值,哈希值决定了在表中的位置。

       

      以下是哈希表的一些关键特性:
      1. 哈希函数:哈希表使用哈希函数将键映射到表中一个位置来存储对应的值。理想的哈希函数应该容易计算,并且能够将不同的键均匀分布到哈希表中。
      2. 冲突解决:由于哈希函数可能会将不同的键映射到同一个位置,这种情况称为“冲突”。解决冲突的方法有多种,比如链地址法(在同一位置存储多个元素,形成一个链表),开放寻址法(寻找下一个空位置)等。
      3. 查找效率:在理想情况下,哈希表的查找、插入和删除操作的时间复杂度可以达到O(1)。然而,在最坏的情况下(例如,所有键都映射到同一个位置),这些操作的时间复杂度可能会退化到O(n)。
      4. 动态扩容:当哈希表中的元素数量达到一定比例时,哈希表可能会进行扩容,以维持操作的效率。扩容通常涉及创建一个更大的表,并将所有现有元素重新哈希到新表中。
      5. 负载因子:负载因子是哈希表中元素数量与哈希表大小的比例。通常,当负载因子超过某个阈值时,哈希表会进行扩容。

      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://blog.csdn.net/2302_79376097/article/details/143216710,作者:禁默,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:数据结构之位图与布隆过滤器

      下一篇:初始JavaEE篇——多线程(8):JUC的组件

      相关文章

      2025-05-19 09:04:14

      复杂度的OJ练习

      复杂度的OJ练习

      2025-05-19 09:04:14
      代码 , 复杂度 , 思路 , 数组 , 算法
      2025-05-16 09:15:24

      Redis Set集合

      Redis Set集合

      2025-05-16 09:15:24
      set , 个数 , 元素 , 示例 , 集合
      2025-05-16 09:15:24

      如何将一串数字用函数的方法倒过来(C语言)

      如何将一串数字用函数的方法倒过来(C语言)

      2025-05-16 09:15:24
      函数 , 数字 , 数组
      2025-05-16 09:15:24

      jQuery遍历对象、数组、集合

      jQuery遍历对象、数组、集合

      2025-05-16 09:15:24
      jQuery , 对象 , 数组 , 遍历 , 集合
      2025-05-16 09:15:24

      Redis Hash哈希

      Redis Hash哈希

      2025-05-16 09:15:24
      field , hash , Redis , value , 哈希
      2025-05-16 09:15:17

      递归,搜索,回溯算法(3)之穷举,暴搜,深搜,回溯,剪枝

      递归,搜索,回溯算法(3)之穷举,暴搜,深搜,回溯,剪枝

      2025-05-16 09:15:17
      回溯 , 子集 , 数组 , 算法 , 递归
      2025-05-14 10:33:31

      计算机小白的成长历程——习题演练(函数篇)

      计算机小白的成长历程——习题演练(函数篇)

      2025-05-14 10:33:31
      函数 , 字符串 , 数组 , 知识点 , 编写 , 迭代 , 递归
      2025-05-14 10:33:31

      计算机小白的成长历程——数组(1)

      计算机小白的成长历程——数组(1)

      2025-05-14 10:33:31
      strlen , 个数 , 元素 , 内存 , 十六进制 , 地址 , 数组
      2025-05-14 10:33:31

      【数据结构】详细介绍串的简单模式匹配——朴素模式匹配算法

      【数据结构】详细介绍串的简单模式匹配——朴素模式匹配算法

      2025-05-14 10:33:31
      下标 , 元素 , 匹配 , 子串 , 模式匹配 , 算法
      2025-05-14 10:33:25

      超级好用的C++实用库之sha256算法

      SHA-256,英文全称为Secure Hash Algorithm 256-bit,是一种广泛使用的密码散列函数,属于SHA-2家族。

      2025-05-14 10:33:25
      CHP , 参数 , 哈希 , 算法 , 输入
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5275024

      查看更多

      最新文章

      复杂度的OJ练习

      2025-05-19 09:04:14

      如何将一串数字用函数的方法倒过来(C语言)

      2025-05-16 09:15:24

      Redis Set集合

      2025-05-16 09:15:24

      【数据结构】详细介绍串的简单模式匹配——朴素模式匹配算法

      2025-05-14 10:33:31

      超级好用的C++实用库之sha256算法

      2025-05-14 10:33:25

      C++ 11新特性之unique_ptr

      2025-05-14 10:33:16

      查看更多

      热门文章

      Arrays类的使用

      2023-06-08 06:23:00

      python学习(6)——列表元素的添加、删除、修改及排序

      2023-05-22 03:00:29

      C语言结构体与结构体指针的使用

      2023-03-08 10:38:36

      C++入门篇之C++ 指针

      2023-03-14 11:26:53

      指针(*)、取地址(&)、解引用(*)与引用(&)

      2023-04-10 08:54:19

      Python打乱列表/数组原顺序,新列表/数组中元素随机分布

      2023-04-13 09:36:44

      查看更多

      热门标签

      java Java python 编程开发 代码 开发语言 算法 线程 Python html 数组 C++ 元素 javascript c++
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      【C++动态规划】1043. 分隔数组以得到最大和|1916

      【C++】堆的构建

      【C++二分查找 拆位法】2411. 按位或最大的最小子数组长度

      数据结构【线性表之单链表】

      C++算法:二分查找旋转数组

      考研数据结构之线性表(1.7)——练习题之将顺序表中所有小于表头元素的整数放在前半部分所有大于表头元素的整数放在后半部分(C表示)

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号