算法:滑动窗口

文章目录

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

例题1:长度最小的子数组

长度最小的子数组

在这里插入图片描述
分析:
若暴力枚举,用三重循环列出所有可能:

int n = nums.size();
for(int i = 0; i < n; i++){//以i位置开头的所有子数组for(int j = i; j < n; j++){//以j位置为结尾int n = 0;for(int k = i; k <= j; k++){//依次算出各个子数组的和,然后比较和大于等于target的子数组的长度那个最小n += nums[k];
………………………………………………………………
//时间复杂度 O(N^3)

简单的优化:计算子数组和时不需要每次都从头开始

int n = nums.size();
for(int i = 0; i < n; i++){//以i位置开头的所有子数组int n = 0;for(int j = i; j < n; j++){n += nums[j];//时间复杂度 O(N^2)

因为这道题说数组中的数全为正整数,所以 += 操作后 n 肯定是递增的(单调性) —— 当 n >= target 时就没有继续 += 的必要了,此时 n 就是这个循环中 长度最小的、和大于等于target的子数组的和

以 2 3 1 2 4 3(target = 7) 为例,第一层循环过后,我们知道了以0位置开头的子数组中,2 3 1 2 是我们想要的;第二次循环会从3开始,我们需要再从头开始枚举子数组吗 —— 我们可以记录第一次循环结束位置,然后直接以3 1 2为基础继续

● 根据以上的分析,我们改用两个指针(同向双指针(同向指两个指针都不回退,向着一个方向移动))来实现上述的操作:
在这里插入图片描述

left 和 right 两个“指针”之间形成一个区间,并记录(维护)着这个区间内的信息(子数组和、长度),两个指针从左向右移动的过程中,这个区间就像一个窗口一样在数组中滑动 —— 滑动窗口

以上的思路为:利用单调性,使用“同向双指针(滑动窗口)”优化问题

● 怎么用:
1.left = 0,right = 0
2.进窗口
3.判断 <-> 出窗口

● 这个方法的正确性:
利用单调性,规避了很多没有必要的枚举行为

在暴力解法中若发现了单调性,可以考虑用这个方法

class Solution {
public:int minSubArrayLen(int target, vector<int>& nums) {int n = nums.size(), sum = 0, len = INT_MAX;//结果for(itn left = 0, right = 0; right < n; right++){sum += nums[right];//进窗口(新进入left和right之间的数据,会产生什么影响--sum+=nums[right])while(sum >= target)//判断{len = min(len, right - left + 1);//更新结果 -- 可能在判断后,也可能在出窗口后(因题而异)sum -= num[left++];//出窗口(left++过后,左侧数据不再处于left和right之间)}}return len;}
};

● 时间复杂度:
我们的每一步操作都让 left / right 向右移动,直至最后 -> O(N)

例题2:无重复字符的最长子串

无重复字符的最长子串

在这里插入图片描述
暴力解法:暴力枚举(从左往右依次枚举以左侧数字为开头的满足要求的所有子串)-- 判断满足要求:可以用哈希表储存已遍历子串部分的字符,依次判断字符是否重复

模拟:
在这里插入图片描述

class Solution {
public:int lengthOfLongestSubstring(string s) {int hash[128] = {0};//使用数组模拟哈希表,0表示没有,1出现一次,2出现两次int len = 0;for(int left = 0, right = 0; right < s.size(); right++){hash[s[right]]++;//进窗口while(hash[s[right]] > 1)//判断 hash[s[left++]]--;//出窗口len = max(len, right - left + 1);//更新结果}return len;}
};

例题3:最大连续1的个数 III

最大连续1的个数 III

在这里插入图片描述

问题转化:找出0的个数不超过k个的最长子数组

暴力求解:从左往右依次以每个数为开头,往后找最长可以到哪 ->O(N^2)
模拟示例1:
在这里插入图片描述

class Solution {
public:int longestOnes(vector<int>& nums, int k) {int ret = 0;for(int left = 0, right = 0, zero = 0; right < nums.size(); right++){//zero记录0的个数//对于right而言,1进窗口时不用管if(nums[right] == 0) zero++;//0进窗口while(zero > k)//判断if(nums[left++] == 0) zero--;//出窗口ret = max(ret, right - left + 1);//更新结果}return ret;}
};

例题4:将 x 减到 0 的最小操作数

将 x 减到 0 的最小操作数

在这里插入图片描述
分析:
在这里插入图片描述

正 难 则 反

class Solution {
public:int minOperations(vector<int>& nums, int x) {//题目说了nums[i]>0int sum_ = 0;for(auto e : nums) sum_+= e;int target = sum_ - x;if(target < 0) return -1;//!int n = nums.size(), len = -1;for(int left = 0, right = 0, sum = 0; right < n; right++){sum += nums[right];//入窗口while(sum > target){//判断sum -= nums[left++];//出窗口       }if(sum == target) len = max(len,right - left + 1);//更新结果}return len == -1 ? -1 : n - len;//如果len初始被赋予 0,这地方用len == 0做判断,遇到 target == 0 的情况会出问题}
};

例题5:水果成篮

水果成篮

在这里插入图片描述

class Solution {
public:int totalFruit(vector<int>& fruits) {int n = fruits.size();int hash[100001] = {0};//数组模拟哈希表,表示各水果类型所持数目 //也可以用unordered_map,似乎更方便些//题目说 1 <= fruits.length <= 10^5,结果开10010个空间不给过,合着 <= 10^5的意思是数量级不是具体数呗,这个老六int num = 0, sort = 0;for(int left = 0, right = 0; right < n; right++){if(hash[fruits[right]] == 0) sort++;hash[fruits[right]]++;//入窗口while(sort > 2){if((--hash[fruits[left++]]) == 0)//出窗口sort--;}num = max(num, right - left + 1);}return num;}
};

这个方法我和老师写的几乎一模一样 —— 我终于出息了(

老师用哈希表的演示:

class Solution {
public:int totalFruit(vector<int>& fruits) {unordered_map<int, int> hash;int ret = 0;for(int left = 0, right = 0; right < fruits.size(); 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;}
};

例题6:找到字符串中所有字母异位词

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

在这里插入图片描述
不同于之前的题目的是,这道题的滑动窗口是固定长度的(长度为p的大小)

可以用两个哈希表分别表示 p 中每个字符出现的次数 和 滑动窗口中每个字符出现的次数。通过比较两哈希表是否相同判断异位词

在这里插入图片描述

class Solution {
public:vector<int> findAnagrams(string s, string p) {int hash1[26] = {0};//p中每个字符出现的次数for(auto ch : p) hash1[ch-'a']++;int hash2[26] = {0};//滑动窗口中每个字符出现的次数vector<int> ret;for(int left = 0, right = 0, count = 0; right < s.size(); right++){char in = s[right];//进窗口的字符 hash2[in - 'a']++;//进窗口if(hash2[in - 'a'] <= hash1[in - 'a']) count++;//判断if(right - left >= p.size()){//固定的窗口长度:p.size()char out = s[left++];if(hash2[out - 'a']-- <= hash1[out - 'a']) count--;//出窗口}if(count == p.size()) ret.push_back(left);//更新结果}return ret;}
};

例题7:串联所有单词的子串

串联所有单词的子串

在这里插入图片描述

例题6 的加强版,试着将子串当做一整个数据(就像单个字符一样)

class Solution {
public:vector<int> findSubstring(string s, vector<string>& words) {unordered_map<string, int> hash1;//存储 words 中的子串for(auto& str : words) hash1[str]++;int len = words[0].size();//一个子串的长度,可视作一个整体数据vector<int> ret;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 >= len * words.size()){string out = s.substr(left, len);//出窗口的数据if(hash1.count(out) && hash2[out] <= hash1[out]) count--;hash2[out]--;left += len;//出窗口}if(count == words.size()) ret.push_back(left);}}return ret;}
};

例题8:最小覆盖子串

最小覆盖子串

在这里插入图片描述

分析:
在这里插入图片描述

class Solution {
public:string minWindow(string s, string t) {int hash1[58] = { 0 };//开了57个空间,然后不够……建议直接开128个空间,还省去了后面 -'A' 的麻烦for (auto ch : t) hash1[ch - 'A']++;int hash2[58] = { 0 };int begin = -1, len = INT_MAX;for (int left = 0, right = 0, count = 0; right < s.size(); right++) {char in = s[right];//进窗口数据hash2[in - 'A']++;//进窗口if (hash2[in - 'A'] <= hash1[in - 'A']) count++;while (count == t.size()) {//判断if (right - left + 1 < len) {//更新结果len = right - left + 1;begin = left;}char out = s[left];//出窗口数据if (hash2[out - 'A'] <= hash1[out - 'A']) count--;hash2[out - 'A']--;//出窗口left++;}}return len == INT_MAX ? "" : s.substr(begin, len);}
};

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

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

相关文章

碳视野|全国首个ESG区域行动方案通过,上海政府推进ESG有八“要”

引领绿色转型&#xff0c;共筑低碳未来&#xff01;AMT企源碳管理团队深入解读碳领域政策、概念及标准&#xff0c;分享实践经验&#xff0c;助力产业绿色发展。我们启动“碳视野、碳课堂、碳实践”三大专栏&#xff0c;紧跟碳行业政策动态&#xff0c;以“科普实践分享”为核心…

【python】六个常见爬虫案例【附源码】

大家好&#xff0c;我是博主英杰&#xff0c;整理了几个常见的爬虫案例&#xff0c;分享给大家&#xff0c;适合小白学习 一、爬取豆瓣电影排行榜Top250存储到Excel文件 近年来&#xff0c;Python在数据爬取和处理方面的应用越来越广泛。本文将介绍一个基于Python的爬虫程序&a…

STM32 GPIO的几种工作模式

介绍STM32 GPIO的几种工作模式 1、输出模式 STM32的引脚输出有两种方式&#xff1a; 1、推挽输出 2、开漏输出 1.1 推挽输出 当引脚设置为推挽输出时&#xff0c;P-MOS和N-MOS共同配合工作。 当使用HAL库 //该函数的作用就是将P-MOS导通&#xff0c;N-MOS关…

SqlServer中连续号及断号查询—附源码

效果如下图所示&#xff1a; SqlServer中连续号及断号查询SQL如下&#xff1a; --1.定义临时表 DECLARE TestTemp TABLE(TestCode NVARCHAR(50),TestNum INT )DECLARE DataTemp TABLE(TestCode NVARCHAR(50),TestNumStr NVARCHAR(100) )--2.插入测试数据 INSERT INTO TestT…

国产体脂方案——蓝牙体脂秤方案

蓝牙体脂秤采用的就是BIA生物电阻抗技术&#xff0c;用户仅需1次测量&#xff0c;就能知道身体的脂肪率&#xff0c;水分率&#xff0c;基础代谢率&#xff0c;肌肉量&#xff0c;骨量&#xff0c;蛋白质&#xff0c;BMI&#xff0c;体重&#xff0c;身体的得分&#xff0c;年龄…

Linux:kubernetes(k8s)pod的基础操作(6)

Linux&#xff1a;kubernetes&#xff08;k8s&#xff09;允许在任意节点使用kubectl命令&#xff08;5&#xff09;-CSDN博客https://blog.csdn.net/w14768855/article/details/136460090?spm1001.2014.3001.5501 我在前两张进行了基础环境的一系列搭建&#xff0c;现在就正…

深度学习_18_模型的下载与读取

在深度学习的过程中&#xff0c;需要将训练好的模型运用到我们要使用的另一个程序中&#xff0c;这就需要模型的下载与转移操作 代码&#xff1a; import math import torch from torch import nn from d2l import torch as d2l import matplotlib.pyplot as plt# 生成随机的…

NFTScan :什么是 ERC-404?深入解读 NFT 协议的未来

上月初&#xff0c;ERC-404 成为最首要热门的话题&#xff0c;ERC-404 是由 Pandora 团队在 2 月初为创作者和开发者等开源的实验性代币标准&#xff0c;其混合 ERC-20 / ERC-721 实现&#xff0c;具有原生流动性和碎片化等特点。伴随着早期的发展&#xff0c;越来越多参与者开…

win10安全中心误删文件怎么办?解析恢复与预防策略

在使用Windows 10的过程中&#xff0c;许多用户依赖于其内置的安全中心来保护电脑免受恶意软件的侵害。然而&#xff0c;有时安全中心的误判可能导致重要文件被错误地删除。当面对这种情况时&#xff0c;了解如何恢复误删的文件并掌握预防措施显得尤为重要。本文将为您详细解析…

java常用技术栈,java面试带答案

前言 我们从一个问题引入今天的主题。 在日常业务开发中&#xff0c;我们可能经常听到 DBA 对我们说“不要”&#xff08;注意&#xff1a;不是禁止&#xff09;使用 join&#xff0c;那么为什么 DBA 对 join 这么抵触呢&#xff1f;是 join 本身有问题&#xff0c;还是我们使…

私募证券基金动态-24年2月报

成交量&#xff1a;2月日均9492.60亿元 2024年2月A股两市日均成交9492.60亿元&#xff0c;环比增加30.38%、同比增加5.77%。2月整体15个交易日&#xff0c;有4个单日交易日成交金额过万亿&#xff0c;单日交易日最高成交金额为13576.43亿元&#xff08;2月28日&#xff09;&am…

MySQL 学习笔记(基础篇 Day1)

「写在前面」 本文为黑马程序员 MySQL 教程的学习笔记。本着自己学习、分享他人的态度&#xff0c;分享学习笔记&#xff0c;希望能对大家有所帮助。 目录 0 课程介绍 1 MySQL 概述 1.1 数据库相关概念 1.2 MySQL 数据库 2 SQL 2.1 SQL 通用语法 2.2 SQL 分类 2.3 DDL 2.4 图形…

【leetcode C++】电话号码的字母组合

17. 电话号码的字母组合 题目 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 题目链接 . - 力扣&#xff08;LeetCode&…

1.类和对象-友元

文章目录 1.全局函数做友元代码运行结果 2.类做友元代码运行结果 1.全局函数做友元 思路分析&#xff1a; 正常情况下&#xff0c;全局函数visit()中的ROOM 类变量r是访问不到Building类中的私有成员的。但是通过在Building类中添加使用全局函数做友元&#xff0c;即可访问私有…

什么是ElasticSearch的深度分页问题?如何解决?

在ElasticSearch中进行分页查询通常使用from和size参数。当我们对ElasticSearch发起一个带有分页参数的查询(如使用from和size参数)时,ElasticSearch需要遍历所以匹配的文档直到达到指定的起始点(from),然后返回从这一点开始的size个文档 在这个例子中: 1.from 参数定义…

代码学习记录13

随想录日记part13 t i m e &#xff1a; time&#xff1a; time&#xff1a; 2024.03.06 主要内容&#xff1a;今天的主要内容是二叉树的第二部分哦&#xff0c;主要有层序遍历&#xff1b;翻转二叉树&#xff1b;对称二叉树。 102.二叉树的层序遍历226.翻转二叉树101. 对称二叉…

LeetCode-第67题-二进制求和

1.题目描述 给你两个二进制字符串 a 和 b &#xff0c;以二进制字符串的形式返回它们的和。 2.样例描述 3.思路描述 将两个二进制字符串转换成整型&#xff0c;然后相加后的整型转为二进制字符串 4.代码展示 class Solution(object):def addBinary(self, a, b):# 将字符串…

AI新工具(20240306) mlx-swift-chat Mac运行本地模型;Comflowyspace开源AI图像和视频生成工具

1: mlx-swift-chat 专为 Apple 硅片设计的高效机器学习框架&#xff0c;支持在本地实时运行 LLM 模型&#xff08;如 Llama、Mistral&#xff09; mlx-swift-chat 是一个为苹果系统&#xff08;例如你的笔记本电脑上的Apple Silicon&#xff09;特别设计的机器学习框架 MLX 的…

计划任务和日志

一、计划任务 计划任务概念解析 在Linux操作系统中&#xff0c;除了用户即时执行的命令操作以外&#xff0c;还可以配置在指定的时间、指定的日期执行预先计划好的系统管理任务&#xff08;如定期备份、定期采集监测数据&#xff09;。RHEL6系统中默认已安装了at、crontab软件…

扫码看图的预览效果怎么做?图片的二维码如何在线生成?

图片二维码是现在很常用的一种预览图片的方式&#xff0c;比如照片、海报、动态图、拍摄的图片等类型的内容都可以用二维码的方式在手机上预览。在制作图片二维码时候&#xff0c;现在大多会通过网上的图片二维码生成器来制作&#xff0c;直接用专业的功能&#xff0c;就可以快…