【优选算法篇】:滑动窗口算法--开启高效解题的“窗口”,透过例题看奥秘

news2024/12/25 8:58:41

✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨
✨ 个人主页:余辉zmh–CSDN博客
✨ 文章所属专栏:c++篇–CSDN博客

在这里插入图片描述

文章目录

  • 一.滑动窗口算法
  • 二.例题
    • 1.长度最小的子数组
    • 2.无重复字符的最长字串
    • 3.最大连续一的个数
    • 4.将x减到0的最小操作数
    • 5.水果成篮
    • 6.找到字符串中所有字母异位词
    • 7.串联所有单词的子串
    • 8.最小覆盖子串

一.滑动窗口算法

滑动窗口算法(Sliding Window Algorithm)是一种用于解决数组和字符串相关问题的常用算法。

  • 核心思想

    滑动窗口的核心思想是利用窗口的移动来优化问题的求解过程(通过两个指针同行移动其实就是滑动窗口),避免不必要的重复过程,从而提高算法的效率。它通过维护一个滑动窗口(窗口大小可变),也就是两个通向移动的指针再数组或者字符串上移动,比根据问题的要求进行相应的操作。

  • 关键参数

    • 窗口大小(Window Size):滑动窗口的宽度,决定了窗口中包含的元素个数。
    • 窗口位置(Window Position):由左右边界(也就是两个指针)定义的窗口在数据序列中的当前位置。
    • 滑动步长(Slide Step):每次移动窗口时跨越的数据单位数量。
    • 数据序列(Data Sequence):滑动窗口在其上进行操作的一系列数据,可以是数组,字符串等。
  • 算法流程

    1.初始化窗口:确定窗口的起始位置和结束位置,通常是数组或者字符串的开头或者任意位置。根据问题要求,确定窗口的大小和滑动规则。

    2.移动窗口:使用循环遍历数组或者字符串,根据滑动规则逐步移动窗口。通常是右指针进窗口,左指针出窗口。

    3.跟新状态:在每一步,计算或者更新窗口内的数据,并根据需要更新结果,比如窗口内的大小,最大值,最小值等变量。

    4.结束条件:当窗口的结束位置达到数组或者字符串的末尾时,算法结束。

接下来通过一些例题来讲解如何使用滑动窗口算法。这些例题也是滑动窗口算法的经典实例。

二.例题

1.长度最小的子数组

链接:leetcode.209.长度最小的子数组
题目

在这里插入图片描述

算法原理

在这里插入图片描述

代码实现

int minSubArrayLen(int target,vector<int>& nums){
    //滑动窗口算法
    int left=0;
    int right = 0;

    int sum = 0;
    size_t len=0;
    size_t minlen = -1;

    //右指针进窗口
    while(right<nums.size()){
        sum += nums[right];

        //当和大于目标值时就是左指针出窗口
        if(sum>=target){
            //注意这里一定是左指针小于等于右指针
            while(left<=right&&sum>=target){
                len = right - left + 1;
                if(len<minlen){
                    minlen = len;
                }

                sum -= nums[left];
                left++;
            }
        }

        right++;
    }

    return minlen != -1 ? minlen : 0;
}

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

链接:leetcode.3.无重复字符的最长子串
题目

在这里插入图片描述

算法原理

在这里插入图片描述

代码实现

int lengthOfLongestSubstring(string s) {
    int left = 0, right = 0;

    int maxlen = 0;
    //定义一个set类型的哈希表
    unordered_set<char> hash;

    while(right<s.size()){
        //进窗口
        pair<unordered_set<char>::iterator,bool> p=hash.insert(s[right]);

        //当插入失败时,也就是遇到重复字符
        if(p.second==false){
            //出窗口,移动左指针找到重复的字符位置,移动加删除
            while(s[left]!=*(p.first)){
                hash.erase(s[left++]);
            }
            //当找到重复的字符时,删除左指针指向的该字符,插入右指针指向的该字符
            hash.erase(s[left++]);
            hash.insert(s[right]);
        }

        //更新最长字串的长度
        maxlen = max(maxlen, right - left + 1);
        right++;
    }

    return maxlen;
}

3.最大连续一的个数

链接:leetcode.1004.最大连续一的个数
题目

在这里插入图片描述

算法原理

在这里插入图片描述

代码实现

int longestOnes(vector<int>& nums,int k){
    //定义左右指针
    int left = 0, right = 0;
    int maxlen = 0;
    int zero = 0;

    while(right<nums.size()){
        if(nums[right]==0){
            zero++;
        }
        if(zero>k){
            while(nums[left]){
                left++;
            }
            zero--;
            left++;
        }

        maxlen = max(maxlen, right - left + 1);

        right++;
    }

    return maxlen;
}

4.将x减到0的最小操作数

链接:leetcode.1658.将x减到0的最小操作数
题目

在这里插入图片描述

算法原理

在这里插入图片描述

代码实现

int minOperations(vector<int>& nums,int x){
    //计算数组总和
    int count = 0;
    for(auto e : nums){
        count += e;
    }

    //目标值等于数组总和减去x
    int target = count - x;
    //当出现特殊情况,就是目标值等于0,说明减去整个数组,直接返回数组长度,就是最小操作数
    if(target==0){
        return nums.size();
    }
    int sum = 0;

    int left = 0, right = 0;
    int maxlen = 0;

    while(right<nums.size()){
        //进窗口
        sum += nums[right];

        //当子数组和大于目标值时,出窗口
        if(sum>target){
            while(left<right&&sum>target){
                sum -= nums[left++];
            }
        }
        //当等于目标值时,就是要找的子数组,计算子数组长度并更新sum值
        if(sum==target){
            maxlen = max(maxlen, right - left + 1);
            sum -= nums[left++];
        }
        right++;
    }

    //如果最大数组长度不为0,最小操作数就是数组长度减去最大数组长度
    int minoperations=-1;
    if(maxlen){
        minoperations = nums.size() - maxlen;
    }

    return minoperations;
}

5.水果成篮

链接:leetcode.904.水果成篮
题目

在这里插入图片描述

算法原理

在这里插入图片描述

代码实现

int totalFruit(vector<int> &fruits)
{
    unordered_map<int, int> hash;

    int left = 0, right = 0;
    int maxlen = 0;

    //记录哈希桶的个数
    int bucket = 0;

    while (right < fruits.size())
    {
        // 进窗口,移动右指针
        hash[fruits[right]]++;
        //当某元素第一次插入时,桶的个数加一
        if (hash[fruits[right]] == 1)
        {
            bucket++;
        }


        //当桶的个数大于二时,水果种类超过三种,要移除一种
        if (bucket > 2)
        {
            //出窗口,直到桶的个数,也就是水果种类小于等于2
            while (left < right && bucket > 2)
            {
                hash[fruits[left]]--;
                if (hash[fruits[left]] == 0)
                {
                    hash.erase(fruits[left]);
                    bucket--;
                }
                left++;
            }
        }

        //更新子数组的最大长度
        maxlen = max(maxlen, right - left + 1);

        right++;
    }

    return maxlen;
}

6.找到字符串中所有字母异位词

链接:leetcode.438.找到字符串中所有字母异位词
题目

在这里插入图片描述

算法原理

在这里插入图片描述

代码实现

vector<int> findAnagrams(string s,string p){
    //定义两个哈希表分别用来存储两个字符串,建立字符和字符个数的映射关系
    unordered_map<char, int> hashs;
    unordered_map<char, int> hashp;
    //定义一个数组用来存储结果
    vector<int> v;

    //定义左右指针
    int left=0,right=0;
    //定义一个变量用来记录字符的有效个数
    int count = 0;

    for(auto e : p){
        hashp[e]++;
    }

    while(right<s.size()){
        //进窗口
        hashs[s[right]]++;
        //如果哈希表s中存放字符个数小于哈希表p中的个数,count加一
        if(hashs[s[right]]<=hashp[s[right]]){
            count++;
        }

        //判断条件
        if(right-left+1>p.size()){
            //出窗口
            if(hashs[s[left]]<=hashp[s[left]]){
                count--;
            }
            hashs[s[left]]--;
            if(hashs[s[left]]==0){
                hashs.erase(s[left]);
            }
            left++;
        }

        //更新结果
        if(count==p.size()){
            v.push_back(left);
        }

        right++;
    }

    return v;
}

7.串联所有单词的子串

链接:leetcode.30.串联所有单词的字串
题目

在这里插入图片描述

算法原理

在这里插入图片描述

代码实现

vector<int> findSubstring(string s, vector<string> &words)
{
    // 定义两个哈希表用来存储字符串,建立字符串和个数之间的映射关系
    unordered_map<string, int> hashs;
    unordered_map<string, int> hashw;
    vector<int> v;

    for (auto e : words)
    {
        hashw[e]++;
    }

    int left = 0, right = 0;
    int count = 0;
    // len是words数组中每个单词的长度
    int len = words[0].size();
    int size = words[0].size();

    // pr字符串是右指针移动区间的字符串,pl字符串是左指针移动区间的字符串
    string pr;
    string pl;
    while (size--)
    {
        while (right < s.size())
        {
            // 进窗口,每次获取len长度的字符串
            pr.clear();
            while (len && len--)
            {
                pr += s[right++];
            }

            hashs[pr]++;
            len = words[0].size();

            if (hashs[pr] <= hashw[pr])
            {
                // 有效字符串的个数加一
                count++;
            }

            // 判断条件
            if ((right - left) > len * words.size())
            {
                // 左指针移动,获取len长度的字符串
                pl.clear();
                while (len && len--)
                {
                    pl += s[left++];
                }

                if (hashs[pl] <= hashw[pl])
                {
                    count--;
                }

                hashs[pl]--;
                if (hashs[pl] == 0)
                {
                    hashs.erase(pl);
                }
                len = words[0].size();
            }

            // 更新结果
            if (count == words.size())
            {
                v.push_back(left);
            }
        }
        left = right = words[0].size() - size;
        count = 0;
        hashs.clear();
    }

    return v;
}

8.最小覆盖子串

链接:leetcode.76.最小覆盖子串
题目

在这里插入图片描述

算法原理

在这里插入图片描述

代码实现

string minWindow(string t, string s)
{
    // 定义两个哈希表,用来建立字符和个数之间的映射关系
    unordered_map<char, int> hasht;
    unordered_map<char, int> hashs;

    // 将字符串t的字符映射到哈希表t中
    int bucket = 0;
    for (auto e : t)
    {
        hasht[e]++;
        // 统计哈希表t的字符种类
        if (hasht[e] == 1)
        {
            bucket++;
        }
    }

    // 定义左右指针,count变量记录哈希表s中的字符种类,有效字符个数
    int left = 0, right = 0;
    int count = 0;

    // begin字串的起始位置,用来更新结果,minlen记录最小字串的长度
    int begin = -1;
    int minlen = INT_MAX;

    while (right < s.size())
    {
        // 进窗口
        hashs[s[right]]++;

        // 两个哈希表中的字符映射关系相等时,count加一
        if (hashs[s[right]] == hasht[s[right]])
        {
            count++;
        }

        // 判断条件,字符种类相等
        while (count == bucket)
        {
            // 更新结果
            minlen = min(minlen, right - left + 1);
            if (minlen == right - left + 1)
            {
                begin = left;
            }

            // 出窗口
            if (hashs[s[left]] == hasht[s[left]])
            {
                count--;
            }
            hashs[s[left]]--;
            if (hashs[s[left]] == 0)
            {
                hashs.erase(s[left]);
            }
            left++;
        }

        right++;
    }

    // 如果没有找到,begin还是初始值返回空字符串,否则返回字串
    return begin == -1 ? "" : s.substr(begin, minlen);
}

以上就是关于滑动窗口算法的讲解,如果哪里有错的话,可以在评论区指正,也欢迎大家一起讨论学习,如果对你的学习有帮助的话,点点赞关注支持一下吧!!!
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2255559.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

调用大模型api 批量处理图像 保存到excel

最近需要调用大模型&#xff0c;并将结果保存到excel中&#xff0c;效果如下&#xff1a; 代码&#xff1a; import base64 from zhipuai import ZhipuAI import os import pandas as pd from openpyxl import Workbook from openpyxl.drawing.image import Image from io i…

CEEMDAN-CPO-VMD二次分解(CEEMDAN+冠豪猪优化算法CPO优化VMD)

CEEMDAN-CPO-VMD二次分解&#xff08;CEEMDAN冠豪猪优化算法CPO优化VMD&#xff09; 目录 CEEMDAN-CPO-VMD二次分解&#xff08;CEEMDAN冠豪猪优化算法CPO优化VMD&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 首先运用CEEMDAN对数据进行一次分解&#xff…

Bloom 效果

1、Bloom 效果是什么 Bloom效果&#xff08;中文也可以叫做高光溢出效果&#xff09;&#xff0c;是一种使画面中亮度较高的区域产生一种光晕或发光效果的图像处理技术&#xff0c;Bloom效果的主要目的是模拟现实世界中强光源在相机镜头或人眼中造成的散射和反射现象&#xff…

【ArkTS】列表组件的“下拉刷新”和“上拉加载”

系列文章目录 【ArkTS】关于ForEach的第三个参数键值 【ArkTS】“一篇带你读懂ForEach和LazyForEach” 【小白拓展】 【ArkTS】“一篇带你掌握TaskPool与Worker两种多线程并发方案” 【ArkTS】 一篇带你掌握“语音转文字技术” --内附详细代码 【ArkTS】技能提高–“用户授权”…

Otter数据同步原理

otter是阿里巴巴的开源的一款数据数据同步工具&#xff0c;它基于对数据库增量日志解析&#xff0c;准实时同步到本机房或者异地机房的mysql/oracle/mq等&#xff0c;是一个分布式数据同步系统。otter第一版本可追溯到04~05年&#xff0c;开发时间从2011年7月份一直持续到现在&…

【已解决】黑马点评项目中-实战篇11-状态登录刷新章节设置RefreshTokenInterceptor拦截器后登录异常的问题

黑马点评项目中-实战篇11-状态登录刷新章节设置RefreshTokenInterceptor拦截器后登录异常的问题 在 MvcConfig 文件中添加好RefreshTokenInterceptor拦截器 出现异常情况 按照验证码登录后&#xff0c;进入主页面&#xff0c;再点击“我的”&#xff0c;又跳入登录界面 原因…

AI - RAG中的状态化管理聊天记录

AI - RAG中的状态化管理聊天记录 大家好&#xff0c;今天我们来聊聊LangChain和LLM中一个重要的话题——状态化管理聊天记录。在使用大语言模型(LLM)的时候&#xff0c;聊天记录&#xff08;History&#xff09;和状态&#xff08;State&#xff09;管理是非常关键的。那我们先…

记一次跑前端老项目的问题

记一次跑前端老项目的问题 一、前言二、过程1、下载依赖2、启动项目3、打包 一、前言 在一次跑前端老项目的时候&#xff0c;遇到了一些坑&#xff0c;这里记录一下。 二、过程 1、下载依赖 使用 npm install下载很久&#xff0c;然后给我报了个错 core-js2.6.12: core-js…

使用Goland对6.5840项目进行go build出现异常

使用Goland对6.5840项目进行go build出现异常 Lab地址: https://pdos.csail.mit.edu/6.824/labs/lab-mr.html项目地址: git://g.csail.mit.edu/6.5840-golabs-2024 6.5840运行环境: mac系统 goland git clone git://g.csail.mit.edu/6.5840-golabs-2024 6.5840 cd 6.5840/src…

Thonny IDE + MicroPython + ESP32 + GY-302 测量环境中的光照强度

GY-302是一款基于BH1750FVI光照强度传感器芯片的模块。该模块能够直接测量出环境中的光照强度&#xff0c;并将光照强度转换为数字信号输出。其具体参数如下表所示。 参数名称 参数特性 测量范围 0-65535 LX 测量精度 在环境光下误差小于20%&#xff0c;能够自动忽略50/60…

网站打开速度测试工具:互联网优化的得力助手

在信息飞速流转的互联网时代&#xff0c;网站如同企业与用户对话的窗口&#xff0c;其打开速度直接关乎用户体验&#xff0c;乃至业务的成败。所幸&#xff0c;一系列专业的网站打开速度测试工具应运而生&#xff0c;它们宛如幕后的技术侦探&#xff0c;精准剖析网站性能&#…

2024数字科技生态大会 | 紫光展锐携手中国电信助力数字科技高质量发展

2024年12月3日至5日&#xff0c;中国电信2024数字科技生态大会在广州举行&#xff0c;通过主题峰会、多场分论坛、重要签约及合作发布等环节&#xff0c;与合作伙伴共绘数字科技发展新愿景。紫光展锐作为中国电信的战略合作伙伴受邀参会&#xff0c;全面呈现了技术、产品创新进…

Matlab R2024b 中文版 下载及安装教程

点击下方链接下载安装包 Matlab R2024b 中文版安装包点击下载https://mp.weixin.qq.com/s/Kq2j1dQLdULOVV9vrA6pkA 安装教程 1.通过上方链接下载软件&#xff0c;鼠标右键【MATLAB R2024b(64bit)】压缩包&#xff0c;选择解压到MATLAB R2024b(64bit)。 2.双击进入解压后的文…

输入法:点三下输入一个汉字

作者常用的双拼输入法&#xff0c;需要26键。虽然也有9键的方案&#xff0c;但重码率较高。计算一下&#xff0c;9键点2下&#xff0c;共81种排列组合。而汉字的读音&#xff0c;不计声调&#xff0c;有400多个。相差甚多。 所以&#xff0c;设计了“三拼输入法”&#xff0c;…

Windows设备go环境安装配置

一、下载go安装包 官网链接&#xff1a;All releases - The Go Programming Language (google.cn) 安装过程比较简单&#xff0c;这里不再赘述&#xff0c;可参考这位博主的文章。本文重点在环境配置。golang环境详细安装、配置_golang安装-CSDN博客 二、环境变量配置 1.添…

简易图书管理系统

javawebjspservlet 实体类 package com.ghx.entity;/*** author &#xff1a;guo* date &#xff1a;Created in 2024/12/6 10:13* description&#xff1a;* modified By&#xff1a;* version:*/ public class Book {private int id;private String name;private double pri…

电子信息工程自动化 单片机自动门控制系统设计

摘 要 伴随着社会经济的发展进步、科学技术的发展进步以及人民群众日常生活质量的逐渐提升&#xff0c;自动门开始全面进入人民群众的生活&#xff0c;逐渐发展成为了宾馆、大型超市、政府等当代建筑里必须配备的设备&#xff0c;是建筑自动智能化综合水平的主要标准之一。它具…

深度解析 Ansible:核心组件、配置、Playbook 全流程与 YAML 奥秘(上)

文章目录 一、ansible的主要组成部分二、安装三、相关文件四、ansible配置文件五、ansible 系列 一、ansible的主要组成部分 ansible playbook&#xff1a;任务剧本&#xff08;任务集&#xff09;&#xff0c;编排定义ansible任务集的配置文件&#xff0c;由ansible顺序依次执…

【银河麒麟操作系统真实案例分享】内存黑洞导致服务器卡死分析全过程

了解更多银河麒麟操作系统全新产品&#xff0c;请点击访问 麒麟软件产品专区&#xff1a;https://product.kylinos.cn 开发者专区&#xff1a;https://developer.kylinos.cn 文档中心&#xff1a;https://documentkylinos.cn 现象描述 机房显示器连接服务器后黑屏&#xff…

# issue 8 TCP内部原理和UDP编程

TCP 通信三大步骤&#xff1a; 1 三次握手建立连接; 2 开始通信&#xff0c;进行数据交换; 3 四次挥手断开连接&#xff1b; 一、TCP内部原理--三次握手 【第一次握手】套接字A∶"你好&#xff0c;套接字B。我这儿有数据要传给你&#xff0c;建立连接吧。" 【第二次…