Sliding Window¶
Problem types¶
Monotonic deque to acheive O(n)¶
- If we need to find the max/min from a sliding window. The first idea would be use ordered container to store them and then access the max/min. But it usually requires O(nlogn) or even worse. While we use deque in sliding window problem we can achieve runtime complexity of O(n) e.g. 1425. Constrained Subsequence Sum, 1438. Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit
- The general idea is to use deque to keep only the necessary information. During each iteration, we use the window size and the order info to keep the invariant:
- All elements that are not possible to become a solution are removed from queue;
- All elements in the queue form a valid window size, so that we can calculate the solution.
- Another caveat is when we maintain the invariant, should we use
while
or useif
? This is realative easy to determine in practice, you just need to verify whether the invariant is maintained correctly. Useif
for one operation andwhile
for multiple operations.
Problems¶
209. Minimum Size Subarray Sum¶
- Solution 1: Using two pointers
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int n = nums.size();
int res = n + 1;
int left = 0;
int sum = 0;
for (int i = 0; i < n; ++i) {
sum += nums[i];
while (sum >= target) {
res = min(res, i - left + 1);
sum -= nums[left];
left++;
}
}
return res == n + 1 ? 0 : res;
}
};
239. Sliding Window Maximum¶
- Solution 1 Use Deque
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n = nums.size();
vector<int> res;
deque<int> deq;
for (int i = 0; i < n; i++) {
// keep the non increasing element in the deque
while (!deq.empty() && nums[i] >= nums[deq.back()]) {
deq.pop_back();
}
deq.push_back(i);
// i reach to the size of the window, add result
if (i >= k - 1) res.push_back(nums[deq.front()]);
// using if (not while) because add one element to the deque
if (deq.front() <= i - k + 1) deq.pop_front(); // to ensure the window size is k
}
return res;
}
};
862. Shortest Subarray with Sum at Least K¶
904. Fruit Into Baskets¶
992. Subarrays with K Different Integers¶
930. Binary Subarrays With Sum¶
1004. Max Consecutive Ones III¶
1234. Replace the Substring for Balanced String¶
1248. Count Number of Nice Subarrays¶
1358. Number of Substrings Containing All Three Characters¶
1425. Constrained Subsequence Sum¶
- Solution 1 Use ordered data structure to keep the min and max.
- Solution 2 Use deque to optimize into linear complexity.
class Solution {
public:
int constrainedSubsetSum(vector<int>& nums, int k) {
int n = nums.size();
multiset<int> s{INT_MIN};
int res = INT_MIN;
vector<int> dp(n);
for (int i = 0; i < n; ++i) {
if (i > k)
// note here j - i <= k, len <= k + 1, i - len is
// the first legitimate element before ith element
s.erase(s.equal_range(dp[i - k - 1]).first);
dp[i] = max(*s.rbegin(), 0) + nums[i];
s.insert(dp[i]);
res = max(res, dp[i]);
}
return res;
}
};
class Solution {
public:
int constrainedSubsetSum(vector<int>& nums, int k) {
int n = nums.size();
vector<int> dp(n);
deque<int> q;
int res = INT_MIN;
for (int i = 0; i < n; ++i) {
if (i > k && q.front() == i - k - 1) {
q.pop_front();
}
dp[i] = (q.empty() ? 0 : max(dp[q.front()], 0)) + nums[i];
// maintain invariant in the sliding window
while (!q.empty() && dp[i] >= dp[q.back()])
q.pop_back();
q.push_back(i);
res = max(res, dp[i]);
}
return res;
}
};
1438. Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit¶
- Solution 1 Use ordered data structure to keep the min and max.
- Solution 2 Use deque to optimize into linear complexity.
class Solution {
public:
int longestSubarray(vector<int>& nums, int limit) {
multiset<int> mset;
int left = 0;
int res = 0;
for (int i = 0; i < nums.size(); ++i) {
mset.insert(nums[i]);
// maintain the invariant
while (*mset.rbegin() - *mset.begin() > limit) {
mset.erase(mset.equal_range(nums[left++]).first);
}
res = max(res, i - left + 1);
}
return res;
}
};
class Solution {
public:
int longestSubarray(vector<int>& nums, int limit) {
deque<int> min_deq;
deque<int> max_deq;
int left = 0;
int res = 0;
// O(n), enque once, deque once.
for (int i = 0; i < nums.size(); ++i) {
// invariant: only keep the min in the deque
while (!min_deq.empty() && nums[i] < min_deq.back())
min_deq.pop_back();
min_deq.push_back(nums[i]);
// invariant: only keep the max in the deque
while (!max_deq.empty() && nums[i] > max_deq.back())
max_deq.pop_back();
max_deq.push_back(nums[i]);
// invariant: move the left point to meet the constrain
while (max_deq.front() - min_deq.front() > limit) {
if (max_deq.front() == nums[left]) max_deq.pop_front();
if (min_deq.front() == nums[left]) min_deq.pop_front();
left++;
}
// up date the result
res = max(res, i - left + 1);
}
return res;
}
};