leetcode 滑动窗口小结 (一)
目录
- 小结以及代码框架
- 76. 最小覆盖子串
- 滑动窗口
- 代码以及注释
- 567. 字符串的排列
- 滑动窗口
- 438. 找到字符串中所有字母异位词
- 3. 无重复字符的最长子串
- 化简框架
- reference
小结以及代码框架
滑动窗口技巧属于双指针技巧。
该算法的思路为维护一个窗口,不断滑动,然后更新答案。
大致框架如下:[参考labuladong的算法小抄]
int left = 0, right = 0;while(right < s.size())
{//增大窗口window.add(s[right]);right++;while(window needs shrink){//缩小窗口window.remove(s[left]);left++;}
}
主要的细节问题:
1、如何向窗口中添加新元素
2、如何缩小窗口
3、在窗口滑动的哪个阶段更新结果
//滑动窗口算法框架
void slidingWindow(string s, string t)
{unordered_map<char,int> need, window;for(char c : t) need[c]++;int left = 0, right = 0;int valid = 0;while(right < s.size()){//c是将要移入窗口的元素char c = s[right];//右移窗口right++;//进行窗口内数据更新(右移窗口)/*******************//**debug输出位置***/cout << "window:[ "<<left << " , " << right <<"]"<<endl;/******************///判断左侧窗口是否需要收缩while(window needs shrink){//d是将移出窗口的字符char d = s[left];//左移窗口left++;//进行窗口内数据的一系列更新(左移窗口)}}
}
76. 最小覆盖子串
https://leetcode-cn.com/problems/minimum-window-substring/
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
注意:如果 s 中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入:s = “ADOBECODEBANC”, t = “ABC”
输出:“BANC”
示例 2:
输入:s = “a”, t = “a”
输出:“a”
提示:
1 <= s.length, t.length <= 10^5
s 和 t 由英文字母组成
滑动窗口
1、初始化window和need两个哈希表,记录下窗口中的字符以及需要凑齐的字符:
unordered_map<char,int> need,window;
for(char c : t) need[c]++;
2、使用left和right变量初始化窗口两端,区间是左闭右开,初始情况下,窗口内是没有元素的。
int left = 0, right = 0;
while(right < s.size())
{//开始滑动
}
3、定义记录变量
valid_length表示window内满足need条件的字符个数,如果valid_length == need.size() 说明窗口已经满足了条件,已经完全覆盖了串T。
int valid_length;
在right向右扩充的时候,对新进来的元素进行检查,如果它是need中的元素,window中对应这个元素就要+1,然后判断window中这个元素的个数是不是need中这个元素的个数相同,如果相同说明这个元素在window中已经找完了,这时候就需要将valid_length+1了
4、套用模板
确定四个问题的具体细节:
1、当right移动,扩大window,应该更新哪些数据?
更新window计数器
2、当left移动,缩小window,应该更新哪些数据?
更新window计数器
3、什么条件下暂停扩大window,开始移动left缩小window?
当valid长度等于need大小时,应该收缩窗口
4、结果应该在扩大窗口时还是缩小窗口时进行?
缩小窗口的时候进行更新结果
代码以及注释
class Solution {public:string minWindow(string s, string t) {unordered_map<char,int> window,need;//记录下t中有哪些元素以及每个元素的个数for(char c : t) need[c]++;//初始化窗口边界int right = 0, left = 0;//window满足need条件的元素个数int valid_length = 0;//结果字符串在s中的起始地址以及长度,这样就不要每次更新整个string了int start = 0 , length = INT_MAX;while(right < s.size()){//******************扩充窗口**************//扩充窗口right++;//扩充进来的新元素char c = s[right - 1]; //判断该元素是否是need中元素if(need.count(c)){window[c]++;if(window[c] == need[c]) valid_length++;}//*******************缩小窗口*************//如果need中所有元素都在window内,并且每个元素的频数也与window内元素频数相同,那么此时就得到了一个答案,记录答案,然后缩小窗口,以获得更优的答案while(valid_length == need.size()){//如果此次答案比上次的答案长度要小,我们才更新答案if(right - left < length){start = left;length = right - left;}//左边界向左移动left++;//d是刚移出窗口的元素char d = s[left - 1];//如果need中出现了dif(need.count(d)){//如果之前d元素在window和need出现的频数相同if(window[d] == need[d]){//删除了之后,频数不相同了,所以这个元素也就不满足了。valid_length--;}window[d]--;}}}//如果length没有更新,说明s不存在t中字符或者不满足字符频数,返回空字符串,否则,使用substr将子串返回return length == INT_MAX ? "" : s.substr(start,length);}
};
567. 字符串的排列
https://leetcode-cn.com/problems/permutation-in-string/
给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。
换句话说,第一个字符串的排列之一是第二个字符串的子串。
示例1:
输入: s1 = “ab” s2 = “eidbaooo”
输出: True
解释: s2 包含 s1 的排列之一 (“ba”).
示例2:
输入: s1= “ab” s2 = “eidboaoo”
输出: False
注意:
输入的字符串只包含小写字母
两个字符串的长度都在 [1, 10,000] 之间
滑动窗口
精确化题目为:假设给你一个S和T,请问S中是否存在一个子串,包含T中所有字符且不包含其他字符
精确化本题细节:
1、移动left缩小窗口的时机:窗口大小大于t的大小,因为各种排列的长度应该是一样的。
2、当valid_length == need.size()时,说明窗口中的数据是一个合法的数据,应该立即返回true;
class Solution {public:bool checkInclusion(string s1, string s2) {unordered_map<char,int> window,need;for(char c : s1) need[c]++;int left = 0,right = 0;int valid_length = 0;while(right < s2.size()){//扩充windowright++;char c = s2[right - 1];if(need.count(c)){window[c]++;if(window[c] == need[c]) valid_length++;}//缩小windowwhile(right - left >= s1.size()){if(valid_length == need.size()) return true;left++;char d = s2[left - 1];if(need.count(d)){if(window[d] == need[d]) valid_length--;window[d]--;}}}return false;}
};
438. 找到字符串中所有字母异位词
https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/
给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。
字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。
说明:
字母异位词指字母相同,但排列不同的字符串。
不考虑答案输出的顺序。
示例 1:
输入:
s: “cbaebabacd” p: “abc”
输出:
[0, 6]
解释:
起始索引等于 0 的子串是 “cba”, 它是 “abc” 的字母异位词。
起始索引等于 6 的子串是 “bac”, 它是 “abc” 的字母异位词。
** 示例 2:**
输入:
s: “abab” p: “ab”
输出:
[0, 1, 2]
解释:
起始索引等于 0 的子串是 “ab”, 它是 “ab” 的字母异位词。
起始索引等于 1 的子串是 “ba”, 它是 “ab” 的字母异位词。
起始索引等于 2 的子串是 “ab”, 它是 “ab” 的字母异位词。
直接套模板
class Solution {public:vector<int> findAnagrams(string s, string p) {if(s.empty()) return {};vector<int> result;unordered_map<char,int> need,window;for(char c : p) need[c]++;int left = 0,right = 0;int valid_length = 0;while(right < s.size()){//expand windowright++;char c = s[right - 1];if(need.count(c)){window[c]++;if(window[c] == need[c]){valid_length++;}}//shrink windowwhile(right - left >= p.size()){if(valid_length == need.size()){result.emplace_back(left);}left++;char d = s[left - 1];if(need.count(d)){if(window[d] == need[d]){valid_length--;}window[d]--;}}}return result;}
};
3. 无重复字符的最长子串
之前做过,这次用滑动窗口模板做:
https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
示例 4:
输入: s = “”
输出: 0
提示:
0 <= s.length <= 5 * 10^4
s 由英文字母、数字、符号和空格组成.
化简框架
将need、valid去除,更新窗口数据只需要更新window计数器。
当window[c]大于1,说明窗口内存在重复字符,不符合条件,就应该移动left缩小窗口。
对于更新结果:更新结果的操作放在收缩窗口之后,因为收缩之后窗口不存在重复字符。
class Solution {public:int lengthOfLongestSubstring(string s) {if(s.empty()) return 0;int res = 0;unordered_map<char,int> window;int left = 0, right = 0;while(right < s.size()){//expand windowright++;char c = s[right -1];window[c]++;//如果进入窗口的新元素在窗口内有重复元素,就需要移动left//shrink windowwhile(window[c] > 1){left++;window[s[left - 1]]--;}res = max(res,right - left);}return res;}
};
reference
《labuladong的算法小抄》
leetcode 滑动窗口小结 (一)相关推荐
- leetcode 滑动窗口小结 (三)
目录 978. 最长湍流子数组 题目 思路分析以及代码 1052. 爱生气的书店老板 题目 思考分析与初步代码 优化思路以及优化代码 1208. 尽可能使字符串相等 题目 思考分析以及代码 978. ...
- leetcode 滑动窗口小结 (二)
目录 424. 替换后的最长重复字符 思考分析1 优化 1004. 最大连续1的个数 III 友情提醒 方法1,基于当前最大频数 方法2,基于历史最大频数 424. 替换后的最长重复字符 https: ...
- leetcode 滑动窗口1
leetcode 滑动窗口1 leetcode159. 至多包含两个不同字符的最长子串 1. 题目 2. 解答 leetcode1151. 最少交换次数来组合所有的1 1. 题目 2. 解答 leet ...
- LeetCode 滑动窗口(Sliding Window)类问题总结
导语 滑动窗口类问题是面试当中的高频题,问题本身其实并不复杂,但是实现起来细节思考非常的多,想着想着可能因为变量变化,指针移动等等问题,导致程序反复删来改去,有思路,但是程序写不出是这类问题最大的障碍 ...
- 数据结构算法——滑动窗口问题(以LeetCode滑动窗口题为例)
1. 滑动窗口 滑动窗口算法是在给定特定窗口大小的数组或字符串上执行要求的操作,它的原理与网络传输TCP协议中的滑动窗口协议(Sliding Window Protocol)基本一致. 这种技术可以将 ...
- leetcode 滑动窗口
滑动窗口 文章目录 滑动窗口 模板框架 [76. 最小覆盖子串](https://leetcode-cn.com/problems/minimum-window-substring/) 思路分析 代码 ...
- LeetCode滑动窗口最大值
题目要求: 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧.你只可以看到在滑动窗口内的 k 个数字.滑动窗口每次只向右移动一位. 返回滑动窗口中的最大值. 示 ...
- leetcode 滑动窗口—— 209/1456
一.209长度最小的子数组 1.题目 https://leetcode-cn.com/problems/minimum-size-subarray-sum/ 给定一个含有 n 个正整数的数组和一个正整 ...
- 【leetcode个人练习记录】 滑动窗口的问题
1.从本质上来看 ,滑窗是双指针,一根指针指向左端点,一根指针指向右端点. 2.右指针移动是可以表示扩张窗口,左指针移动表示缩小窗口. 3.如果当前元素满足需求时,可以挪动右指针尝试更优解,并且更新需 ...
最新文章
- webpack笔记(6)调试模式
- NeuralRecon:单目视频的实时Coherent 三维重建
- python SMTP发送邮件常出现问题
- 转载:2014年流行的手机App小图标界面设计欣赏(1)
- 大数据开发实战:数据仓库技术
- //输入学生人数,挨个输入姓名,身高,年龄,求平均年龄,然后按身高降序排列输出...
- Android的联通性---USB主机模式(三)
- 【view桌面虚拟化系列】1-vSphere搭建
- Django - rest - framework - 下
- 国外云服务器有哪些?国外云服务器大全
- QQ连连看外挂核心算法(消除一对棋子)
- 计算机断电无法启动不了系统,电脑突然断电后无法启动怎么回事
- “欢迎来到智能城市,我是小武”
- 公司监事会的职责具体是什么
- Visual Studio Code,一款功能强大且轻巧的免费代码集成编辑器介绍
- 基于UFEI下的win10 + Ubuntu18.04双系统攻略!!!
- HDLBits—Lemmings3
- T-SQL openquery 删除报错 “键列信息不足或不正确。更新影响到多行”
- a卡gpuz,MSI Afterburner显卡不显示温度,启动OverdriveNTool提示atiadlxx.dll不存在的错误
- 计蒜之道2019 复赛 D-星云系统(单调栈)
热门文章
- vue 子父组件周期顺序_父组件和子组件生命周期钩子执行顺序是什么?
- 实战sqlmap绕过WAF
- php16进制密钥签名对接支付,简单理解rsa的加密和签名-PHP实现
- android 使用c 代码实现,JNI开发实现helloworld,调用自己的C代码实现(1)
- (1)《Head First HTML与CSS》学习笔记---HTML基本概念
- react-native 热更新react-native-pushy集成遇到的问题
- web前端-回调函数sort详解
- PhantomJS宣布终止开发
- Mysql远程登录及常用命令
- 简单的GTK窗体搭建