C++ 滑动窗口

news2024/12/24 20:13:02

目录

1、209. 长度最小的子数组

2、3. 无重复字符的最长子串

3、1004. 最大连续1的个数 III

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

5、904. 水果成篮

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

7、30. 串联所有单词的子串

8、76. 最小覆盖子串


1、209. 长度最小的子数组

 思路:使用双指针技巧和滑动窗口的思想,通过不断调整左右指针的位置来找到和大于等于目标值的最短子数组的长度。

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;
    }
};
  1. 初始化变量n为数组nums的长度,sum为0(用于记录当前子数组的和),len为INT_MAX(用于记录最短子数组的长度)。
  2. 使用双指针技巧,初始化左指针left和右指针right都指向数组的起始位置。
  3. 进入循环,循环条件是右指针right小于数组长度。
  4. 在循环中,将当前元素nums[right]加到sum中,表示扩展当前子数组。
  5. 如果sum大于等于目标值target,则进入内部循环。
  6. 在内部循环中,更新最短子数组的长度len,取当前长度right - left + 1和之前的最短长度len的较小值。
  7. 然后,从当前子数组中减去左指针所指向的元素,并将左指针向右移动一位。
  8. 重复步骤6和7,直到sum小于目标值target
  9. 返回最短子数组的长度len,如果len仍然是INT_MAX,则说明没有找到符合条件的子数组,返回0。

2、3. 无重复字符的最长子串

思路:通过数组模拟哈希表,每次遍历到字母时,其ASCII码值对应数组的位置加一,如果right位置出现次数大于一,则left和right对应字母相等,只需减少数组left位置减一然后left加一即可。每次遍历结束都计算与上次相比的最大长度。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int hash[128] = {0}, n = s.size(), len = 0;
        for (int left = 0, right = 0; right < n; right++) {
            hash[s[right]]++;
            while (hash[s[right]] > 1) {
                hash[s[left++]]--;
            }
            len = max(len, right - left + 1);
        }
        return len;
    }
};

3、1004. 最大连续1的个数 III

思路:每次首先统计零出现次数,如果出现次数大于k,也就是超过可翻转0的个数时,通过while循环更新left位置。每次遍历最后计算长度。

class Solution {
public:
    int longestOnes(vector<int>& nums, int k) {
        int zero = 0, len = 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;
    }
};

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

思路:寻找和等于<数组之和减x>的连续元素代替两端找元素,总长度减去其长度即为所求。

class Solution {
public:
    int minOperations(vector<int>& nums, int x) {
        int n = nums.size(), sum = 0;
        for (auto a : nums)
            sum += a;
        int target = sum - x, tmp = 0;
        if (target < 0)//处理sum小于x的情况
            return -1;
        int ret = -1;
        for (int left = 0, right = 0; right < n; right++) {
            tmp += nums[right];
            while (tmp > target)
                tmp -= nums[left++];
            if (tmp == target)
                ret = max(ret, right - left + 1);
        }
        if (ret == -1)//没有符合的返回-1
            return ret;
        else
            return n - ret;
    }
};

5、904. 水果成篮

 

 思路:哈希表+滑动窗口

class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        unordered_map<int, int> hash;
        int ret = 0, n = fruits.size();
        for (int left = 0, right = 0; right < n; right++) {
            hash[fruits[right]]++;
            while (hash.size() > 2) {
                hash[fruits[left]]--;
                if (hash[fruits[left]] == 0)
                    hash.erase(fruits[left]);
                left++;
            }
            ret = max(ret, right - left + 1);
        }
        return ret;
    }
};
  1. 首先,使用一个unordered_map hash来记录当前窗口中每种水果的数量。
  2. 定义一个变量ret来记录最长的连续子数组的长度,初始值为0。
  3. 使用两个指针left和right来表示窗口的左右边界,初始时两个指针都指向数组的第一个元素。
  4. 在循环中,右指针right向右移动,将当前水果加入到hash中,并增加其数量。
  5. 如果hash中不同水果的种类数大于2,说明窗口中包含了超过两种不同类型的水果,需要移动左指针left来缩小窗口。
  6. 移动左指针时,将左边界对应的水果数量减少1,并判断减少后的数量是否为0,如果为0,则从hash中删除该水果。
  7. 不断移动左指针,直到窗口中不再包含超过两种不同类型的水果。
  8. 在每次移动左指针后,更新ret的值,即为当前窗口的长度。
  9. 最后返回ret,即为最长的连续子数组的长度。

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

思路: 滑动窗口+哈希表

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> ret;
        int hash1[26] = {0};
        for (auto a : p) {
            hash1[a - 'a']++;
        }
        int hash2[26] = {0};
        int count = 0;
        for (int left = 0, right = 0; right < s.size(); right++) {
            char in = s[right];
            if (++hash2[in - 'a'] <= hash1[in - 'a'])
                count++;
            if (right - left + 1 > p.size()) {
                char out = s[left++];
                if (hash2[out - 'a']-- <= hash1[out - 'a'])
                    count--;
            }
            if (count == p.size())
                ret.push_back(left);
        }
        return ret;
    }
};
  1. 首先,定义一个vector ret来存储结果,即符合条件的字母异位词的起始索引。
  2. 使用一个大小为26的数组hash1来记录字符串p中每个字符出现的次数。
  3. 使用两个大小为26的数组hash2和count来记录当前窗口中每个字符出现的次数和符合条件的字符个数。
  4. 使用两个指针left和right来表示窗口的左右边界,初始时两个指针都指向字符串s的第一个字符。
  5. 在循环中,右指针right向右移动,将当前字符加入到hash2中,并增加其出现次数。
  6. 如果hash2中当前字符的出现次数不超过hash1中的出现次数,说明当前字符是符合条件的字符,将count加1。
  7. 如果窗口的长度超过了字符串p的长度,需要移动左指针left来缩小窗口。
  8. 移动左指针时,将左边界对应的字符从hash2中减少出现次数,并判断减少后的次数是否小于等于hash1中的次数,如果小于等于,则说明减少后的字符不再符合条件,将count减1。
  9. 不断移动左指针,直到窗口的长度等于字符串p的长度。
  10. 在每次移动左指针后,判断count是否等于字符串p的长度,如果等于,则说明窗口中包含了一个字母异位词,将左指针的索引加入到结果数组ret中。
  11. 最后返回ret,即为所有符合条件的字母异位词的起始索引。

7、30. 串联所有单词的子串

思路:滑动窗口+哈希表

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        unordered_map<string, int> hash1;
        vector<int> ret;
        for (auto& s : words) {
            hash1[s]++;
        }
        int len = words[0].size(), slen = words.size();
        for (int i = 0; i < len; i++) {
            unordered_map<string, int> hash2;
            for (int left = i, right = i, count = 0; right + len <= s.size();
                 right += len) {
                string in = s.substr(right, len);
                hash2[in]++;
                if (hash1.count(in) && hash2[in] <= hash1[in]) {
                    count++;
                }
                if (right - left + 1 > len * slen) {
                    string out = s.substr(left, len);
                    if (hash1.count(out) && hash2[out] <= hash1[out]) {
                        count--;
                    }
                    hash2[out]--;
                    left += len;
                }
                if (count == slen) {
                    ret.push_back(left);
                }
            }
        }
        return ret;
    }
};
  1. 首先,使用一个unordered_map(哈希表)hash1来记录words中每个字符串出现的次数。
  2. 然后,定义一个vector ret来存储结果,即符合条件的子串的起始索引。
  3. 接下来,通过两层循环来遍历s中的所有可能的子串。外层循环是根据words中字符串的长度来确定的,内层循环是遍历s中的每个字符。
  4. 在内层循环中,首先使用substr函数从s中截取长度为len的子串in,并将其加入到另一个unordered_map(哈希表)hash2中,并增加其出现次数。
  5. 然后,判断in是否在hash1中出现,并且hash2中的出现次数不超过hash1中的出现次数,如果满足条件,则将count加1。
  6. 接着,判断当前子串的长度是否超过了words中所有字符串的总长度,如果超过了,则需要移动左边界,即将左边界对应的子串从hash2中移除,并更新count的值。
  7. 最后,判断count是否等于words中字符串的个数,如果等于,则说明当前子串包含了words中所有字符串,将左边界的索引加入到ret中。
  8. 最后返回ret,即为所有符合条件的子串的起始索引。

8、76. 最小覆盖子串

思路:滑动窗口+哈希表

class Solution {
public:
    string minWindow(string s, string t) {
        int hash1[128] = {0}, kinds = 0;
        for (auto s : t) {
            if (hash1[s]++ == 0) {
                kinds++;
            }
        }
        int hash2[128] = {0}, count = 0, minlen = INT_MAX, begin = -1;
        for (int left = 0, right = 0; right < s.size(); right++) {
            char in = s[right];
            if (++hash2[in] == hash1[in]) {
                count++;
            }
            while (count == kinds) {
                if (right - left + 1 < minlen) {
                    minlen = right - left + 1;
                    begin = left;
                }
                char out = s[left++];
                if (hash2[out]-- == hash1[out]) {
                    count--;
                }
            }
        }
        if (begin == -1) {
            return "";
        } else {
            return s.substr(begin, minlen);
        }
    }
};
  1. 首先,使用一个大小为128的数组hash1来记录字符串t中每个字符出现的次数,并使用一个变量kinds来记录不同字符的种类数。
  2. 使用两个大小为128的数组hash2和count来记录当前窗口中每个字符出现的次数和符合条件的字符种类数。
  3. 使用两个指针left和right来表示窗口的左右边界,初始时两个指针都指向字符串s的第一个字符。
  4. 在循环中,右指针right向右移动,将当前字符加入到hash2中,并增加其出现次数。
  5. 如果hash2中当前字符的出现次数等于hash1中的出现次数,说明当前字符是符合条件的字符,将count加1。
  6. 如果窗口中包含了字符串t中的所有字符,即count等于kinds,进入内层循环。
  7. 在内层循环中,首先判断当前窗口的长度是否小于最小窗口长度minlen,如果是,则更新minlen和begin的值。
  8. 然后,移动左指针left来缩小窗口,将左边界对应的字符从hash2中减少出现次数,并判断减少后的次数是否等于hash1中的次数,如果是,则说明减少后的字符不再符合条件,将count减1。
  9. 不断移动左指针,直到窗口中不再包含字符串t中的所有字符。
  10. 在每次移动左指针后,继续移动右指针来扩大窗口,重复步骤4-9,直到右指针到达字符串s的末尾。
  11. 最后,判断begin的值是否为初始值-1,如果是,则说明没有找到符合条件的窗口,返回空字符串;否则,根据begin和minlen截取最小窗口子串,并返回。

​ 

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

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

相关文章

超越传统—Clean架构打造现代Android架构指南

超越传统—Clean架构打造现代Android架构指南 1. 引言 在过去几年里&#xff0c;Android应用开发经历了巨大的变革和发展。随着移动设备的普及和用户对应用的期望不断提高&#xff0c;开发人员面临着更多的挑战和需求。传统的Android架构在应对这些挑战和需求时显得有些力不从…

计算机网络-物理层传输介质(导向传输介质-双绞线 同轴电缆 光纤和非导向性传输介质-无线波 微波 红外线 激光)

文章目录 传输介质及分类导向传输介质-双绞线导向传输介质-同轴电缆导向传输介质-光纤非导向性传输介质小结 传输介质及分类 物理层规定电气特性&#xff1a;规定电气信号对应的数据 导向传输介质-双绞线 双绞线的主要作用是传输数据和语音信息。它通过将两根导线以特定的方…

【Effective Objective - C】—— 协议与分类

【Effective Objective - C】—— 协议与分类 23.通过委托与数据源协议进行对象间通信协议委托模式数据源模式 要点 24.将类的实现代码分散到便于管理的数个分类之中要点 25.总是为第三方类的分类名称加前缀要点 26.勿在分类中声明属性要点&#xff1a; 27.使用 “class-contin…

cleanmymacX有必要买吗

CleanMyMac X是一款被广泛推荐的Mac电脑清理软件。以下是关于是否购买CleanMyMac X的几个关键点&#xff1a; 软件功能&#xff1a;CleanMyMac X具备多项功能&#xff0c;包括但不限于系统垃圾清理、缓存清理、恶意软件移除、隐私保护等。这些功能有助于保持Mac电脑的清洁和性能…

数据可视化市场概览:五款主流工具的优缺点解析

在数据可视化的世界中&#xff0c;选择一款合适的工具对于提升工作效率和洞察力至关重要。本文将为您介绍五款主流数据可视化工具&#xff0c;包括山海鲸可视化、Echarts、D3.js、Tableau和Power BI&#xff0c;并进行详细比较&#xff0c;帮助您做出明智的选择。 山海鲸可视化…

【数据结构】(二)线性表List

目录 1、基本概念 2、栈&#xff08;Stack&#xff09; 3、队列&#xff08;Queue&#xff09; 4、串&#xff08;String&#xff09; 1、基本概念 &#xff08;1&#xff09;线性表是零或多个数据元素的有限序列。 &#xff08;2&#xff09;数组长度指存储空间长度&…

一键给家长私发成绩

各位老师&#xff0c;你们是否也有过这样的经历&#xff1a;每到考试后&#xff0c;为了将学生的成绩一一发给家长&#xff0c;费尽心思地整理、核对&#xff0c;甚至有时候还要加班。如今&#xff0c;有了易查分&#xff0c;这一切似乎变得轻松起来。但这个功能真的是老师们的…

【教学类-44-04】20240130 print dashed(虚线字体)制作的数字描字帖

作品展示&#xff1a;背景需求&#xff1a; 制作绿色数字的数字描字帖 选用字体&#xff1a;print dashed&#xff08;虚线字体&#xff09; 【教学类-44-03】20240111阿拉伯数字字帖的字体&#xff08;三&#xff09;——德彪钢笔行书&#xff08;实线字体&#xff09;和pri…

Java玩转《啊哈算法》排序之快速排序

心无挂碍&#xff0c;无挂碍故&#xff0c;无有恐怖&#xff0c;远离颠倒梦想&#xff0c;究竟涅槃。 地图 引子代码地址快速排序核心代码优劣完整代码演示 课后习题 引子 搭嘎好&#xff01;本人最近看的《啊哈算法》这本书写的确实不错&#xff0c;生动形象&#xff0c;在保…

详解SpringCloud微服务技术栈:深入ElasticSearch(2)——自动补全、拼音搜索

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;详解SpringCloud微服务技术栈&#xff1a;深入ElasticSearch&#xff08;1&#xff09;——数据聚合 &#x1f4da;订阅专栏&…

STM32——温湿度LCD显示并上传手机

STM32——温湿度LCD显示并上传手机 1.LCD1602 硬件接线 D0~D7 – A0~A7 RS – B1 RW – B2 EN – B10 V0 – GND&#xff08;正视看不到显示结果&#xff0c;需要侧着看。否则需要接可调电阻&#xff09; 引脚封装 RS、RW、EN三根信号线经常需要进行拉高/拉低操作&…

JAVAEE初阶 网络编程(八)

IP协议 认识IP协议 在认识IP协议之前&#xff0c;我们首先要明确IP协议的工作范围或者是用途。 &#xff08;1&#xff09; 地址管理&#xff1a;使用一套地址体系&#xff0c;来描述互联网上各个设备所处的为止。 &#xff08;2&#xff09; 路由选择&#xff1a;数据包如何从…

使用linux进程管理工具supervisor管理你的多个应用进程(支持web界面)

前言 supervisor可以帮你管理进程&#xff0c;你只需要编写配置文件&#xff0c;supervisor便可以方便控制启动&#xff0c;暂停&#xff0c;重启某个进程&#xff0c;你可以编写进程启动命令&#xff0c;来控制supervisor要进行的操作 流程 安装 sudo yum update sudo yum…

U2net:Going deeper with nested u-structure for salient object detection

u2net是目前stable-diffusion-webui默认的抠图算法&#xff0c;但是在电商图场景实测下来&#xff0c;效果是很一般的。 1.introduction 1.能否设计一个新的网络用语SOD&#xff0c;允许从头训练&#xff1b;2.保持高分辨率特征图的同时网络更深。U2net是一种为SOD设计的两级…

3671系列矢量网络分析仪

01 3671系列矢量网络分析仪 产品综述&#xff1a; 3671系列矢量网络分析仪产品包括3671C&#xff08;100kHz&#xff5e;14GHz&#xff09;、3671D&#xff08;100kHz&#xff5e;20GHz&#xff09;、3671E&#xff08;100kHz&#xff5e;26.5GHz&#xff09;、3671G&#x…

性能评测工具+数据库主从复制方案

PTS&#xff08;Performance Testing Service&#xff09; 面向所有技术背景人员的云化测试工具 MSQL MGR 8.0 高可用 对性能影响比较大的参数 MyBatis 数据库主从复制 解决方案1 方案2 主从复制经典架构

Gateway API 实践之(六)FSM Gateway 的健康检查功能

FSM Gateway 流量管理策略系列&#xff1a; 故障注入黑白名单访问控制限速重试会话保持健康检查负载均衡算法TLS 上游双向 TLS 网关的健康检查功能是一种自动化监控机制&#xff0c;用于定期检查和验证后端服务的健康状况&#xff0c;确保流量只被转发到那些健康且能正常处理请…

机器学习算法-----K-近邻算法

1.1 K-近邻算法简介 1.定义: 就是通过你的"邻居"来判断你属于哪个类别 2.如何计算你到你的"邻居"的举例 一般时候&#xff0c;都是使用欧氏距离 1.2k近邻算法api初步使用 1.sklearn 优势: 1.文档多&#xff0c;且规范&#xff0c…

谷达冠楠:抖音开店怎么运营好

在数字营销的海洋中&#xff0c;抖音如同一艘快艇&#xff0c;以其独特的视频形式和庞大的用户基础成为商家们的新宠。开店容易&#xff0c;运营难。要想在抖音上成功运营店铺&#xff0c;需要掌握一些核心技巧。 首当其冲的是内容创意。抖音的用户喜好多变&#xff0c;因此&am…

AI 神助攻,协同办公神器 ---- ONLYOFFICE

人工智能不会取代人&#xff0c;只会淘汰那些不会使用人工智能的人。 – 鲁迅 一、人工智能重新定义办公新模式 随着GPT的横空出世&#xff0c;AI的应用场景已经无处不在&#xff0c;从智能客服、智能语音助手、智能家居到自动驾驶汽车等&#xff0c;AI正在不断地拓展其应用领…