Slide Window 专题
209. Minimum Size Subarray Sum
给定正整数数组和正整数s,找到加和大于等于s的连续子数组的最小长度。
基础slide window题目。
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int ret = INT_MAX, win_size = , len = nums.size(), sum = ;
for(int i=; i<len; i++){
sum += nums[i];
win_size++;
while(sum >= s && win_size > ){
ret = min(ret, win_size);
sum -= nums[i-win_size+];
win_size--;
}
}
return ret==INT_MAX ? : ret;
}
};
862. Shortest Subarray with Sum at Least K
209加强版,与上一题唯一不同的地方在于,数组中存在负数。
Detailed intuition behind deque solution 这份题解写得特别好。其中就上一题209讲解了滑动窗口算法工作的基本原理:
Incremeting the end pointer while the sum of current subarray (defined by current values of
startandend) is smaller than the target.Once we satisfyour condition (the sum of current subarray >= target) we keepincrementingthe start pointer until weviolateit (untilsum(array[start:end+1]) < target).Once we violate the condition we keep incrementing the end pointer until the condition is satisfied again and so on.
也讲解了为什么在有负数的情况下,传统滑动窗口算法不能工作:
The problem with this solution is that it doesn't work if we have negative values, this is because of the sentence above Once we "violate" the condition we stop incrementing start.
同时举例说明:
Now, let's take an example with negative values nums = [3, -2, 5] and target=4. Initially start=0, we keep moving the end pointer until we satisfy the condition, here we will have start=0 and end=2. Now we are going to move the start pointer start=1. The sum of the current subarray is -2+5=3 < 4 so we violate the condition. However if we just move the start pointer another time start=2 we will find 5 >= 4 and we are satisfying the condition. And this is not what the Sliding window assumes.
引出deque改进的滑动窗口算法:
What does the Deque store :
deque保存start指针可能的值,因为deque需要保证单调递增,所以不一定是连续。
The deque stores the possible values of the start pointer. Unlike the sliding window, values of the start variable will not necessarily be contiguous.
Why is it increasing :
之所以维护递增的队列,是为了保证,当d[0]不满足条件时,d[i] i>0 都不满足条件。这样一来才能适用于滑动窗口算法。
So that when we move the start pointer and we violate the condition, we are sure we will violate it if we keep taking the other values from the Deque. In other words, if the sum of the subarray from start=first value in the deque to end is smaller than target, then the sum of the subarray from start=second value in the deque to end is necessarily smaller than target.
So because the Deque is increasing (B[d[0]] <= B[d[1]]), we have B[i] - B[d[0]] >= B[i] - B[d[1]], which means the sum of the subarray starting from d[0] is greater than the sum of the sub array starting from d[1].
Why do we have a prefix array and not just the initial array like in sliding window :
由于deque里的值不是连续的,所以不能像传统滑动窗口(start指针的取值是连续变化)那样仅通过一个sum来维护每个窗口的和。因此需要维护前缀和来求得每个窗口的和。
Because in the sliding window when we move start (typically when we increment it) we can just substract nums[start-1] from the current sum and we get the sum of the new subarray. Here the value of the start is jumping and one way to compute the sum of the current subarray in a constant time is to have the prefix array.
Why using Deque and not simply an array :
既然需要从start端取数,又需要从end端取数,还需要从end端插入数,因此使用deque。
We can use an array, however we will find ourselves doing only three operations:
1- remove_front : when we satisfy our condition and we want to move the start pointer
2- append_back : for any index that may be a future start pointer
3- remove_back : When we are no longer satisfying the increasing order of the array
Deque enables doing these 3 operations in a constant time.
解法:
首先计算nums的前缀和P。对于每个下标有y,我们希望找到opt(y),opt(y)是最大的 x(x<y),使得 P[y]-P[x] >= k。
- 若存在 x2>x1 ,且P[x2] <P[x1],那么opt(y)一定不是x1,因为 P[y] - P[x2] >= P[y] - P[x1],且 y - x2 < y - x1
- 若已存在opt(y1)==x,那么x就不用再被考虑,因为若存在y2 > y1,opt(y2)==x,y2-x > y1-x
维护一个存有P下标的单调队列,当把idx入到队尾前,需将队尾满足P[tail] > P[idx]的tail出队。
若对头head,满足P[y]-P[head] >= k,则将head弹出。
class Solution {
public:
int shortestSubarray(vector<int>& nums, int k){
int len = nums.size(), result = len+;
vector<long long> prefix(len+, );
for(int i=; i<=len; i++)
prefix[i] = prefix[i-] + nums[i-];
deque<int> mono_q;
mono_q.push_back();
for(int i=; i<=len; i++){
while(!mono_q.empty() && prefix[i] - prefix[mono_q.front()] >= k){
result = min(result, i - mono_q.front());
mono_q.pop_front();
}
while(!mono_q.empty() && prefix[mono_q.back()] >= prefix[i])
mono_q.pop_back();
mono_q.push_back(i);
}
return result==len+ ? - : result;
}
};
992. Subarrays with K Different Integers
给定一个正整数数组,计算刚好有K个不同数的子数组的个数。(For example, [1,2,3,1,2] has 3 different integers: 1, 2, and 3.)
解法一:slide window
如果是求最多有K个不同元素的子数组,那么就是典型的slide window的题目,只需要在这个典型题目上增添一步:
exactly(K) = atMost(K) - atMost(K-1)
class Solution {
public:
int subarraysWithKDistinct(vector<int>& A, int K) {
//cout<<atMost(A, K)<<" "<<atMost(A, K-1)<<endl;
return atMost(A, K) - atMost(A, K-);
}
int atMost(vector<int> &A, int K){
map<int, int> count;
int ret = , win_size = , len = A.size(), ctr = ;
for(int i=; i<len; i++){
if(count[A[i]] == ){
ctr++;
}
count[A[i]]++;
while(ctr > K){
if((--count[A[i-win_size--]]) == )
ctr--;
}
++win_size;
//cout<<i<<" "<<win_size<<endl;
ret += (win_size);
}
return ret;
}
};
解法二:prefix slide window
思路:
如果子数组[j, i]包含K个不同元素,并且前prefix个元素也出现在子数组[j+prefix, i]中,那么可以得到1+prefix个符合要求的子数组。例如,[1, 2, 1, 2, 3],前两个数[1, 2]也出现在子数组[1,2,3]中,可以得到1+2
个符合要求的子数组,[1, 2, 1, 2, 3], [2, 1, 2, 3] 和 [1, 2, 3].
遍历数组,维护滑动窗口,窗口尾指向当前元素,窗口头head移动至j,使A[j]在窗口中只出现一次。换句话说,在保证不同元素数不变的情况下,尽量缩短窗口。为达到这个目的,对出现在窗口中元素进行计数,当下一个元素添加到窗口尾时,从窗口头移除尽量多的元素,直至窗口头指向的元素仅在窗口中出现一次,在移除元素的同时,递增prefix。
如果窗口中存在K个不同元素,可以得到1+prefix个符合要求的子数组。
如果窗口中有K+1个不同元素,我们需要移除窗口头指向的元素(该元素仅出现在窗口头),因为我们开始计算一组新的子数组所以重置prefix。
class Solution {
public:
int subarraysWithKDistinct(vector<int>& A, int K) {
int len = A.size(), prefix = , head = , ret = ;
map<int, int> count;
for(int i=; i<len; i++){
if(!count[A[i]]++)
K--;
if(K < ){
--count[A[head++]];
prefix = ;
K++;
}
while(count[A[head]] > ){
--count[A[head++]];
prefix++;
}
if(K==)
ret += prefix+;
}
return ret;
}
};
类似题目:
1248. Count Number of Nice Subarrays
解法一:slide window
exactly(K) = atMost(K) - atMost(K-1)
class Solution {
public:
int numberOfSubarrays(vector<int>& nums, int k) {
return atMost(nums, k) - atMost(nums, k-);
}
int atMost(vector<int> &nums, int k){
int len = nums.size(), ret = , head = ;
for(int i=; i<len;i++){
if(nums[i]%)
k--;
while(k<){
if(nums[head++]%)
k++;
}
ret += i-head+;
}
return ret;
}
};
解法二:prefix slide window
class Solution {
public:
int numberOfSubarrays(vector<int>& nums, int k) {
int len = nums.size(), head = , ret = , prefix = ;
for(int i=; i<len; i++){
if(nums[i]%)
k--;
if(k<){
head++;
k++;
prefix = ;
}
while(head<=i && nums[head]%==){
head++;
prefix++;
}
if(k==)
ret += prefix+;
//cout<<k<<" "<<prefix<<endl;
}
return ret;
}
};
395. Longest Substring with At Least K Repeating Characters
求字符串s的子串的最大长度,该子串要求所有字符在该子串中出现的次数都至少是k次。
解法一:滑动窗口
一开始把题目看成了,子串中每个字符至多出现k次。如果是这样,那么是一道典型的滑动窗口的题目。
然而,题目是至少出现k次。这样一来,滑动窗口不再适用。因为,在字符出现至多k次的问题中,当窗口尾部的字符超过k个,意味着只需要将窗口头部往后移动直至尾部字符等于k个;当尾部字符出现次数小于k次时,只需要将窗口尾部继续往后移动即可。而在字符出现至少k次的问题中,当尾部字符出现次数小于k次时,无法判断是移动窗口头部(舍弃尾部当前字符,后面可能不再有窗口尾部的字符)还是移动窗口尾部(期待后面还有更多当前尾部字符)。
在此题中,字符出现的次数不能用来决定窗口的动作(移动头还是移动尾)。但是可以引入别的依据来移动窗口,例如,窗口中不同字符至多多少个。问题从至少转换为至多。那转换后的问题与原问题的关系是什么呢?窗口依照其中出现的不同字符数量移动,我们对窗口中的不同字符(unique)和出现次数大于等于k的字符(at_least_k)进行计数,若对当前窗口unique==at_least_k,说明该窗口中所有不同的字符都至少出现了k次。
class Solution {
public:
int longestSubstring(string s, int k) {
int result = ;
for(int i=; i<=; i++){
int unique = , at_least_k = , win_size = , len = s.size();
unordered_map<char, int> ctr;
for(int j=; j<len; j++){
if(ctr[s[j]]++ == )
unique++;
if(ctr[s[j]] == k)
at_least_k++;
while(unique > i){
if(ctr[s[j-win_size]] == k)
at_least_k--;
if(--ctr[s[j-win_size--]] == )
unique--;
}
win_size++;
if(unique == at_least_k)
result = max(result, win_size);
}
}
return result;
}
};
解法二:分治法 https://www.cnblogs.com/jasonlixuetao/p/11945760.html
Detailed intuition behind Deque solution
Slide Window 专题的更多相关文章
- Siddhi CEP Window机制
https://docs.wso2.com/display/CEP400/SiddhiQL+Guide+3.0#SiddhiQLGuide3.0-Window https://docs.wso2.co ...
- [LeetCode] 76. Minimum Window Substring 解题思路
Given a string S and a string T, find the minimum window in S which will contain all the characters ...
- sliding window:"Marginalization","Schur complement","First estimate jacobin"
[1]知行合一2 SLAM中的marginalization 和 Schur complement SLAM的Bundle Adjustment上,随着时间的推移,路标特征点(landmark)和相机 ...
- EasyPR--开发详解(8)文字定位
今天我们来介绍车牌定位中的一种新方法--文字定位方法(MSER),包括其主要设计思想与实现.接着我们会介绍一下EasyPR v1.5-beta版本中带来的几项改动. 一. 文字定位法 在EasyPR前 ...
- c++堆
c++ reference: http://www.cplusplus.com/reference/algorithm/make_heap/ heap并不属于STL容器组件,它分为 max heap ...
- jquery之右下角消息提示框
messager.js (function (jQuery) { var window; var obj = new Object(); obj.version = '@1.0'; obj.title ...
- [LeetCode] 3. Longest Substring Without Repeating Characters 解题思路
Given a string, find the length of the longest substring without repeating characters. For example, ...
- [LeetCode] Minimum Size Subarray Sum 解题思路
Given an array of n positive integers and a positive integer s, find the minimal length of a subarra ...
- [LeetCode#159] Missing Ranges Strobogrammatic Number
Problem: Given a string, find the length of the longest substring T that contains at most 2 distinct ...
随机推荐
- Linux_FTP服务器
目录 目录 FTP FTP Server FTP configuration Global config Anonymous user FTP Config Virtual user FTP Loca ...
- github javascript相关项目star数排行榜(前30,截止2016.11.18):
github javascript相关项目star数排行榜(前30,截止2016.11.18): 前端开源框架 TOP 100 前端 TOP 100:::::https://www.awesomes. ...
- mysql部署-主从搭建
一.安装数据库 yum -y install http://www.percona.com/downloads/percona-release/redhat/0.1-4/percona-release ...
- C语言I作业12——学习总结
1.我学到的内容 二.我的收获 作业 链接 第一次作业 https://www.cnblogs.com/liuxiangjiang/p/11579877.html 第二次作业 https://www. ...
- h2内嵌数据库使用
参考文档 1 https://www.cnblogs.com/xdp-gacl/p/4171024.html 参考文档 2 https://blog.csdn.net/mafan121/article ...
- Maven-Eclipse使用maven创建HelloWorld Java项目,maven常用的命令解析
1.开发过程常用的maven命令有: mvn clean mvn compile mvn test mvn package mvn install mvn deploy 2.mvn clean:清理t ...
- 【洛谷p2239】螺旋矩阵
关于题前废话: 这道题的数据范围过于强大了qwq,显然如果我们开一个30000*30000的二维数组来模拟,显然首先就开不下这么大的数组,然后暴力搜索的话也会爆掉,所以直接模拟显然是一个不正确的选择( ...
- [BZOJ 2820] YY的gcd(莫比乌斯反演+数论分块)
[BZOJ 2820] YY的gcd(莫比乌斯反演+数论分块) 题面 给定N, M,求\(1\leq x\leq N, 1\leq y\leq M\)且gcd(x, y)为质数的(x, y)有多少对. ...
- poj1011 Sticks (dfs剪枝)
[题目描述] George took sticks of the same length and cut them randomly until all parts became at most 50 ...
- 该项目不知道如何运行配置文件 IIS Express。
项目右键属性-->调试 -->启动改为项目即可