Sliding window first
340. Longest Substring with At Most K Distinct Characters Given a string, find the length of the longest substring T that contains at most k distinct characters. Input: s = "eceba", k = 2 Output: 3
same as #159: longest sub string at most 2 distinct chars. be careful about k = 0. class Solution { public: int lengthOfLongestSubstringTwoDistinct(string s) { unordered_map<char, int> indMap; int len = s.length(); int res = 0; int start = 0; for(int i = 0; i < len; i ++) { char ch = s[i]; if(indMap.find(ch) == indMap.end() && indMap.size() == 2) { char toDelete; int minInd = INT_MAX; for(auto& [c, ind]: indMap) if(ind < minInd) { toDelete = c; minInd = ind; } start = minInd + 1; indMap.erase(toDelete); } res = max(res, i - start + 1); indMap[ch] = i; } return res; } };
1074. Number of Submatrices That Sum to Target Given a matrix, and a target, return the number of non-empty submatrices that sum to target. A submatrix x1, y1, x2, y2 is the set of all cells matrix[x][y] with x1 <= x <= x2 and y1 <= y <= y2. Two submatrices (x1, y1, x2, y2) and (x1', y1', x2', y2') are different if they have some coordinate that is different: for example, if x1 != x1'. Input: matrix = [[0,1,0],[1,1,1],[0,1,0]], target = 0 Output: 4
similar to one problem: find the max rectangle with sum <= K. we use l and r two pointers to indicate the col. we get the sum of each rows from col l to col r. then add up each row and find in set. class Solution { public: int numSubmatrixSumTarget(vector<vector<int>>& matrix, int target) { int rows = matrix.size(); if(rows == 0) return 0; int cols = matrix[0].size(); int res = 0; for(int l = 0; l < cols; l ++) { vector<int> colVec(rows); for(int r = l ; r < cols; r ++) { for(int i = 0; i < rows; i++) { colVec[i] += matrix[i][r]; } multiset<int> nums; nums.insert(0); int sum = 0; for(int i = 0; i < rows; i ++) { sum += colVec[i]; res += nums.count(sum - target); nums.insert(sum); } } } return res; } };
1151. Minimum Swaps to Group All 1's Together Given a binary array data, return the minimum number of swaps required to group all 1's present in the array together in any place in the array. Input: [1,0,1,0,1] Output: 1
the same logic as move stones: 1040. Moving Stones Until Consecutive II. class Solution { public: int minSwaps(vector<int>& data) { int count = 0; vector<int> arr; for(int i = 0; i < data.size(); i ++) { if(data[i] == 1) { count ++; arr.push_back(i); } } if(count < 2) return 0; int l = 0; int res = INT_MAX; for(int r = 0; r < count; r ++) { while(arr[r] - arr[l] >= count) l ++; int inplace = r - l + 1; res = min(res, count - inplace); } return res; } };
159. Longest Substring with At Most Two Distinct Characters Given a string s , find the length of the longest substring t that contains at most 2 distinct characters. Input: "eceba" Output: 3
use char index map to record the latest index of char. then if invalid char is coming, then iterate the index map and erase the smallest index char. class Solution { public: int lengthOfLongestSubstringTwoDistinct(string s) { unordered_map<char, int> indMap; int len = s.length(); int res = 0; int start = 0; for(int i = 0; i < len; i ++) { char ch = s[i]; if(indMap.find(ch) == indMap.end() && indMap.size() == 2) { char toDelete; int minInd = INT_MAX; for(auto& [c, ind]: indMap) if(ind < minInd) { toDelete = c; minInd = ind; } start = minInd + 1; indMap.erase(toDelete); } res = max(res, i - start + 1); indMap[ch] = i; } return res; } };
3. Longest Substring Without Repeating Characters Given a string, find the length of the longest substring without repeating characters. Input: "pwwkew" Output: 3
use two pointers to record l and r. int lengthOfLongestSubstring(string s) { int res = 0; int len = s.length(); if(len == 0) return 0; int l = 0; unordered_set<char> chSet; Loop through set for(int r = 0; r < len; r ++) { char ch = s[r]; if(chSet.find(ch) != chSet.end()) { while(l < len && s[l] != ch) { chSet.erase(s[l]); l ++; } chSet.erase(s[l]) ; l++; } chSet.insert(ch); res = max(res, r - l +1); } return res; } };
1052. Grumpy Bookstore Owner On some minutes, the bookstore owner is grumpy. If the bookstore owner is grumpy on the i-th minute, grumpy[i] = 1, otherwise grumpy[i] = 0. When the bookstore owner is grumpy, the customers of that minute are not satisfied, otherwise they are satisfied. The bookstore owner knows a secret technique to keep themselves not grumpy for X minutes straight, but can only use it once. Return the maximum number of customers that can be satisfied throughout the day. Input: customers = [1,0,1,2,1,1,7,5], grumpy = [0,1,0,1,0,1,0,1], X = 3 Output: 16
we first add up all the non grumpy count. then for first X time, we add the grumpy count. then from index = X to size, we use slide window to update the result. class Solution { public: int maxSatisfied(vector<int>& customers, vector<int>& grumpy, int X) { int size = grumpy.size(); int total = 0; for(int i = 0; i < size; i ++) if(!grumpy[i]) total += customers[i]; for(int i=0; i < X && i < size; i ++) { if(grumpy[i]) total += customers[i]; } int res = total; for(int i = X; i < size; i ++) { if(grumpy[i-X]) total -= customers[i-X]; if(grumpy[i]) total += customers[i]; res = max(res, total); } return res; } };
424. Longest Repeating Character Replacement Given a string s that consists of only uppercase English letters, you can perform at most k operations on that string. In one operation, you can choose any character of the string and change it to any other uppercase English character. Find the length of the longest sub-string containing all repeating letters you can get after performing the above operations Input: s = "AABABBA", k = 1 Output: 4
we keep recording the max count and then the replace count is r - l + 1 - maxCount. class Solution { public: int characterReplacement(string s, int k) { int len = s.length(); int l = 0; int res = 0; int maxCount = 0; unordered_map<char,int> counts; for(int r = 0; r < len ; r ++) { counts[s[r]] ++; maxCount = max(maxCount, counts[s[r]]); int replace = r - l + 1 - maxCount; if(replace > k) { counts[s[l++]] --; replace = r - l + 1 - maxCount; } res = max(res, r - l + 1); } return res; } };
567. Permutation in String Given two strings s1 and s2, write a function to return true if s2 contains the permutation of s1. In other words, one of the first string's permutations is the substring of the second string. Input: s1 = "ab" s2 = "eidbaooo" Output: True
we keep the count map. and keep moving the sliding window, class Solution { public: bool checkInclusion(string s1, string s2) { int m = s1.length(); if(m > s2.length()) return false; unordered_map<char,int> counts; for(auto& ch: s1) counts[ch] ++; unordered_map<char,int> countMap; for(int i = 0; i < m; i ++) { countMap[s2[i]] ++; } if(same(counts, countMap)) return true; for(int i = m; i < s2.length(); i ++) { countMap[s2[i-m]] --; countMap[s2[i]] ++; if(same(counts, countMap)) return true; } return false; } bool same(unordered_map<char,int>& map1, unordered_map<char,int>& map2) { for(auto& [ch, cnt]: map1) { if(map2.find(ch) == map2.end() || map2[ch] < cnt) return false; } return true; } };
992. Subarrays with K Different Integers Given an array A of positive integers, call a (contiguous, not necessarily distinct) subarray of A good if the number of different integers in that subarray is exactly K. (For example, [1,2,3,1,2] has 3 different integers: 1, 2, and 3.) Return the number of good subarrays of A. Input: A = [1,2,1,2,3], K = 2 Output: 7
we keep two windows, one has count > K, another has count >= K. struct win { unordered_map<int, int> counts; void insert(int val) { counts[val] ++; } void erase(int val) { counts[val] --; if(counts[val] == 0) counts.erase(val); } }; class Solution { public: int subarraysWithKDistinct(vector<int>& A, int K) { win left; win right; int ind1 = 0; int ind2 = 0; int res = 0; for(int i = 0; i < A.size(); i ++) { left.insert(A[i]); right.insert(A[i]); while(left.counts.size() > K) { left.erase(A[ind1 ++]); } while(right.counts.size() >= K) { right.erase(A[ind2 ++]); } res += ind2 - ind1; } return res; } };
1004. Max Consecutive Ones III Given an array A of 0s and 1s, we may change up to K values from 0 to 1. Return the length of the longest (contiguous) subarray that contains only 1s. Input: A = [1,1,1,0,0,0,1,1,1,1,0], K = 2 Output: 6 Explanation: [1,1,1,0,0,1,1,1,1,1,1]
we record the count of one, and use l, r two pointers. if (r - l + 1 - count > K) means numbers need to change > K, then move l forward. class Solution { public: int longestOnes(vector<int>& A, int K) { int size = A.size(); int count = 0; int l = 0; int res = 0; for(int r = 0; r < size; r ++) { if(A[r] == 1) count ++; int change = r - l + 1 - count; if(change > K) { while(change > K) { if(A[l] == 1) count --; l ++; change = r - l + 1 - count; } } res = max(res, r - l + 1); } return res; } };
978. Longest Turbulent Subarray A subarray A[i], A[i+1], ..., A[j] of A is said to be turbulent if and only if: For i <= k < j, A[k] > A[k+1] when k is odd, and A[k] < A[k+1] when k is even; OR, for i <= k < j, A[k] > A[k+1] when k is even, and A[k] < A[k+1] when k is odd. That is, the subarray is turbulent if the comparison sign flips between each adjacent pair of elements in the subarray. Return the length of a maximum size turbulent subarray of A. Input: [9,4,2,10,7,8,8,1,9] Output: 5 Explanation: (A[1] > A[2] < A[3] > A[4] < A[5])
we record the diff array. if diff[i]*dif[i-1] < 0, mean it's valid segment, else update res. class Solution { public: int maxTurbulenceSize(vector<int>& A) { int size = A.size(); if(size < 2) return size; vector<int> diff(size); for(int i = size-2; i >= 0 ; i--) { int d = 0; if(A[i+1] > A[i]) d = 1; else if(A[i+1] < A[i]) d = -1; diff[i] = d; } int res = 0; int start = 0; for(int i = 1; i < size; i ++) { if(diff[i] * diff[i-1] < 0) continue; //part of turban else { int len = i - start + 1; if(diff[i-1] == 0) len --; res = max(res, len); start = i; } } return res; } };
1040. Moving Stones Until Consecutive II On an infinite number line, the position of the i-th stone is given by stones[i]. Call a stone an endpoint stone if it has the smallest or largest position. Each turn, you pick up an endpoint stone and move it to an unoccupied position so that it is no longer an endpoint stone. In particular, if the stones are at say, stones = [1,2,5], you cannot move the endpoint stone at position 5, since moving it to any position (such as 0, or 3) will still keep that stone as an endpoint stone. The game ends when you cannot make any more moves, ie. the stones are in consecutive positions. Input: [7,4,9] Output: [1,2] Explanation: We can move 4 -> 8 for one move to finish the game. Or, we can move 9 -> 5, 4 -> 6 for two moves to finish the game.
we store the r and l index. we sort stones. when stones[r] - stones[l] >= sizes, we move l forward. then we can get the already inplace stones: r - l + 1, the moves: size - inplace. class Solution { public: vector<int> numMovesStonesII(vector<int>& stones) { int size = stones.size(); if(size < 3) return {0, 0}; sort(stones.begin(), stones.end()); int l = 0; int minV = INT_MAX; int maxV = 0; for(int r = 0; r < size; r ++) { while(stones[r] - stones[l] >= size) l ++; int inplace = r - l + 1; if(inplace == size-1 && stones[r] - stones[l] + 1 == size - 1) { minV = min(minV, 2); //2,3,7 } else minV = min(minV, size - inplace); } int v1 = stones[size-1] - stones[1] - (size-2); int v2 = stones[size-2] - stones[0] - (size-2); maxV = max(v1, v2); return {minV, maxV}; } };
995. Minimum Number of K Consecutive Bit Flips In an array A containing only 0s and 1s, a K-bit flip consists of choosing a (contiguous) subarray of length K and simultaneously changing every 0 in the subarray to 1, and every 1 in the subarray to 0. Return the minimum number of K-bit flips required so that there is no 0 in the array. If it is not possible, return -1. Input: A = [0,1,0], K = 1 Output: 2
we use flip<int> to record the flip count at each index. class Solution { public: int minKBitFlips(vector<int>& A, int K) { int size = A.size(); if(size == 0) return 0; vector<int> flip(size); int res = 0; for(int i = 0; i + K-1< size; i ++) { flip[i] += (i == 0? 0: flip[i-1]); if( (A[i] == 0 && flip[i] % 2 == 0) || (A[i] == 1 && flip[i] % 2 == 1) ) { flip[i] ++; if(i + K < size) flip[i+K] --; res ++; } } for(int i = size - K + 1; i < size; i ++) { flip[i] += (i == 0? 0: flip[i-1]); if((A[i] == 0 && flip[i] % 2 == 0) || (A[i] == 1 && flip[i] % 2 == 1)) { return -1; } } return res; } };
1100. Find K-Length Substrings With No Repeated Given a string S, return the number of substrings of length K with no repeated characters. Input: S = "havefunonleetcode", K = 5 Output: 6
we use l, r two pointers and countmap. if count[str[r]] > 1, then move l forward. if r - l + 1 > K, move l forward. class Solution { public: int numKLenSubstrNoRepeats(string str, int K) { int len = str.length(); int l = 0; int res = 0; unordered_map<char, int> counts; for(int r = 0; r < len ; r ++) { char ch = str[r]; counts[ch] ++; if(counts[ch] > 1) { while(str[l] != ch) { counts[str[l]] --; l ++; } counts[str[l]] --; l ++; } while(r - l + 1 > K) { counts[str[l]] --; l ++; } if(r - l + 1 == K) { res ++; } } return res; } };
727. Minimum Window Subsequence Given strings S and T, find the minimum (contiguous) substring W of S, so that T is a subsequence of W. If there is no such window in S that covers all characters in T, return the empty string "". If there are multiple such minimum-length windows, return the one with the left-most starting index. S = "abcdebdde", T = "bde" Output: "bcde"
we use next[i][j] to record the next index of char j, from current index i. then we maintain array of windows when iterate each char of t. class Solution { public: string minWindow(string s, string t) { int m = s.length(); int n = t.length(); vector<vector<int>> next(m, vector<int>(26, -1)); vector<int> inds(26, -1); for(int i = m-1; i >= 0; i --) { inds[s[i] -'a'] = i; for(int j = 0; j < 26; j ++) { next[i][j] = inds[j]; } } vector<vector<int>> windows; for(int i = 0; i < m; i ++) { if(s[i] == t[0]) windows.push_back({i, i}); } for(int i = 1; i < n; i ++) { for(auto& win: windows) { if(win[0] == -1 || win[1] == -1) continue; if(win[1] == m-1) { win[0] = -1; win[1] = -1; continue; } int nextInd = next[win[1]+1][t[i] - 'a']; if(nextInd == -1) { win[0] = -1; win[1] = -1; continue; } else { win[1] = nextInd; } } } int start = 0; int minLen = INT_MAX; for(auto& win: windows) { if(win[0] == -1 || win[1] == -1) continue; if(win[1] - win[0] + 1 < minLen) { minLen = win[1] - win[0] + 1; start = win[0]; } } return minLen == INT_MAX? "":s.substr(start, minLen); } };
76. Minimum Window Substring Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n). Input: S = "ADOBECODEBANC", T = "ABC" Output: "BANC"
we use two pointers. if current matched chars == t unique chars, then move left forward. class Solution { public: string minWindow(string s, string t) { int m = s.length(); int n = t.length(); unordered_map<char, int> counts; for(auto& ch: t) counts[ch] ++; int match = 0; int minLen = INT_MAX; int start = -1; int l = 0; int r = 0; while(r < m) { char ch = s[r]; if(counts.find(ch) == counts.end()) { r ++; continue; } counts[ch] --; if(counts[ch] == 0) match ++; if(match == counts.size()) { while(match == counts.size() && l < m) { if(r - l + 1 < minLen) { minLen = r - l + 1; start = l; } if(counts.find(s[l]) == counts.end()) { l ++; continue; } counts[s[l]] ++; if(counts[s[l]] == 1) match --; l ++; } } r ++; } if(start == -1) return ""; return s.substr(start, minLen); } };
480. Sliding Window Median Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. Your job is to output the median array for each window in the original array. For example, Given nums = [1,3,-1,-3,5,3,6,7], and k = 3. Window position Median --------------- ----- [1 3 -1] -3 5 3 6 7 1 1 [3 -1 -3] 5 3 6 7 -1 1 3 [-1 -3 5] 3 6 7 -1 1 3 -1 [-3 5 3] 6 7 3 1 3 -1 -3 [5 3 6] 7 5 1 3 -1 -3 5 [3 6 7] 6
we use two set to maintain left side and right side num. if i >= k, first erase nums[i-k], then insert current to left, and then extract the largest left to right. if right size > left size, extract smallest right to left. class Solution { private: multiset<int> left; multiset<int> right; public: vector<double> medianSlidingWindow(vector<int>& nums, int k) { int size = nums.size(); vector<double> res; for(int i = 0; i < size; i ++) { if(i >= k) { auto ite = left.find(nums[i-k]); if(ite != left.end()) left.erase(ite); else { ite = right.find(nums[i-k]); if(ite != right.end()) right.erase(ite); } } left.insert(nums[i]); auto ite = (--left.end()); right.insert(*ite); left.erase(ite); if(right.size() > left.size()) { auto ite = right.begin(); left.insert(*ite); right.erase(ite); } if(i >= k-1) { double l = *(--left.end()); double r = *(right.begin()); if(k % 2 == 1) res.push_back(l); else { res.push_back((l + r) / 2); } } } return res; } };
239. Sliding Window Maximum Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. Return the max sliding window. Window position Max --------------- ----- [1 3 -1] -3 5 3 6 7 3 1 [3 -1 -3] 5 3 6 7 3 1 3 [-1 -3 5] 3 6 7 5 1 3 -1 [-3 5 3] 6 7 5 1 3 -1 -3 [5 3 6] 7 6 1 3 -1 -3 5 [3 6 7] 7
we used set and deque. class Solution { public: vector<int> maxSlidingWindow(vector<int>& nums, int k) { int size = nums.size(); if(size == 0) return {}; vector<int> res(size - k + 1); deque<int> dq; for(int i = 0; i < k ; i ++) { updateDq(nums, i, dq, k); dq.push_back(i); } res[0] = nums[dq.front()]; for(int i = k; i < size; i ++) { updateDq(nums, i, dq, k); dq.push_back(i); res[i - k + 1] = nums[dq.front()]; } return res; } void updateDq(vector<int>& nums, int ind, deque<int>& dq, int k) { while(!dq.empty() && ind >= dq.front() + k) dq.pop_front(); while(!dq.empty() && nums[ind] > nums[dq.back()]) dq.pop_back(); } vector<int> maxSlidingWindow1(vector<int>& nums, int k) { //use set to insert and erase int size = nums.size(); if(size == 0) return {}; multiset<int> numSet; for(int i = 0; i < k; i ++) { numSet.insert(nums[i]); } vector<int> res(size - k + 1); res[0] = *(--(numSet.end())); for(int r = k; r < size; r ++) { int toDelete = nums[r - k]; auto ite = numSet.find(toDelete); numSet.erase(ite); numSet.insert(nums[r]); res[r-k+1] = *(--numSet.end()); } return res; } };