sliding window选编 难点:
如何判断window满足要求
window满足要求后,如何优化window (start尽可能右移)
目标:
找start
找len
写法一:用HashMap
PS:理论上你可以设计两端都开或者两端都闭的区间,但设计为左闭右开区间是最方便处理的。因为这样初始化 left = right = 0
时区间 [0, 0)
中没有元素,但只要让 right
向右移动(扩大)一位,区间 [0, 1)
就包含一个元素 0
了。如果你设置为两端都开的区间,那么让 right
向右移动一位后开区间 (0, 1)
仍然没有元素;如果你设置为两端都闭的区间,那么初始区间 [0, 0]
就包含了一个元素。这两种情况都会给边界处理带来不必要的麻烦。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 public String minWindow (String s, String t) { HashMap<Character,Integer> need = new HashMap <>(); HashMap<Character,Integer> window = new HashMap <>(); int t_length = t.length(); for (int i = 0 ; i < t_length; i++) { need.put(t.charAt(i),need.getOrDefault(t.charAt(i),0 )+1 ); } int left = 0 ; int right = 0 ; int valid = 0 ; int start = 0 ; int len = Integer.MAX_VALUE; while (right < s.length()){ char c = s.charAt(right); right++; if (need.containsKey(c)){ window.put(c,window.getOrDefault(c,0 )+1 ); if (window.get(c).equals(need.get(c))){ valid++; } } while (valid == need.size()){ if (right - left < len){ len = right - left; start = left; } char d = s.charAt(left); left++; if (need.containsKey(d)){ if (window.get(d).equals(need.get(d))){ valid--; } window.put(d,window.get(d)-1 ); } } } return len = = Integer.MAX_VALUE ? "" : s.substring(start,start+len); }
写法二:用数组
to be continued
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public boolean checkInclusion (String s1, String s2) { Map<Character,Integer> need=new HashMap <>(); for (int i = 0 ; i < s1.length(); i++) { need.put(s1.charAt(i),need.getOrDefault(s1.charAt(i),0 )+1 ); } int valid=0 ; int left=0 ; int right=0 ; Map<Character,Integer> window=new HashMap <>(); while (right<s2.length()){ char c=s2.charAt(right); window.put(c,window.getOrDefault(c,0 )+1 ); right++; if (need.containsKey(c)&&need.get(c).equals(window.get(c))){ valid++; } while (valid==need.size()){ if (right-left==s1.length()){ return true ; } char d=s2.charAt(left); left++; if (need.containsKey(d)){ if (need.get(d).equals(window.get(d))){ valid--; } window.put(d,window.get(d)-1 ); } } } return false ; }
sliding window 模板:
现在开始套模板,只需要思考以下四个问题 :
1、当移动 right
扩大窗口,即加入字符时,应该更新哪些数据?
2、什么条件下,窗口应该暂停扩大,开始移动 left
缩小窗口?
3、当移动 left
缩小窗口,即移出字符时,应该更新哪些数据?
4、我们要的结果应该在扩大窗口时还是缩小窗口时进行更新?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public int lengthOfLongestSubstring (String s) { Map<Character,Integer> map=new HashMap <>(); int left=0 ; int right=0 ; int max=Integer.MIN_VALUE; while (right<s.length()){ char c=s.charAt(right); map.put(c,map.getOrDefault(c,0 )+1 ); right++; while (map.get(c)!=1 ){ char d=s.charAt(left); map.put(d,map.get(d)-1 ); left++; } max=Math.max(max,right-left); } return max==Integer.MIN_VALUE ? 0 : max; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public List<Integer> findAnagrams (String s, String p) { List<Integer> res=new ArrayList <>(); Map<Character,Integer> need=new HashMap <>(); Map<Character,Integer> window=new HashMap <>(); for (int i = 0 ; i < p.length(); i++) { need.put(p.charAt(i),need.getOrDefault(p.charAt(i),0 )+1 ); } int left=0 ; int right=0 ; int start=0 ; int valid=0 ; while (right<s.length()){ char c=s.charAt(right); right++; if (need.containsKey(c)){ window.put(c,window.getOrDefault(c,0 )+1 ); if (need.get(c).equals(window.get(c))){ valid++; } } while (valid==need.size()){ if (right-left==p.length()){ res.add(left); } char d=s.charAt(left); left++; if (window.containsKey(d)){ window.put(d,window.get(d)-1 ); if (need.get(d)>window.get(d)){ valid--; } } } } return res; }
159. Longest Substring with At Most Two Distinct Characters 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public int lengthOfLongestSubstringTwoDistinct (String s) { int n=s.length(); int res=1 ; int l=0 ; int r=0 ; Map<Character,Integer> map=new HashMap <>(); while (r<n){ char c=s.charAt(r++); map.put(c,map.getOrDefault(c,0 )+1 ); while (map.keySet().size()>2 ){ c=s.charAt(l++); map.put(c,map.get(c)-1 ); if (map.get(c)==0 ){ map.remove(c); } } res=Math.max(res,r-l); } return res; }
424. Longest Repeating Character Replacement 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public int characterReplacement (String s, int k) { int n=s.length(); int [] count=new int [26 ]; int left=0 ; int right=0 ; int mostFreqCount=0 ; int res=0 ; while (right<n){ char c=s.charAt(right++); count[c-'A' ]++; mostFreqCount=Math.max(mostFreqCount,count[c-'A' ]); while (right-left-mostFreqCount>k){ char d=s.charAt(left++); count[d-'A' ]--; } res=Math.max(res,right-left); } return res; }
2398. Maximum Number of Robots Within Budget 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public int maximumRobots (int [] chargeTimes, int [] runningCosts, long budget) { int n= chargeTimes.length; int left=0 ; int right=0 ; int res=0 ; PriorityQueue<int []> pq=new PriorityQueue <>((a,b)->(b[1 ]-a[1 ])); long sum=0 ; while (right<n){ sum+=runningCosts[right]; pq.offer(new int []{right,chargeTimes[right]}); right++; while (!pq.isEmpty() && pq.peek()[0 ]<left){ pq.poll(); } long cur=pq.peek()[1 ]+(right-left)*sum; while (cur>budget){ sum-=runningCosts[left++]; while (!pq.isEmpty() && pq.peek()[0 ]<left){ pq.poll(); } if (left<right){ cur=pq.peek()[1 ]+(right-left)*sum; }else { cur=0 ; } } res=Math.max(res,right-left); } return res; }
1151. Minimum Swaps to Group All 1’s Together 注意:
find the subarray of ones length with maximum number of 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public int minSwaps (int [] data) { int ones=0 ; for (int num : data) { if (num==1 ){ ones++; } } if (ones<=1 ){ return 0 ; } int n=data.length; int max=0 ; int left=0 ; int right=0 ; int count=0 ; while (right<n){ if (data[right++]==1 ){ count++; } if (right-left>ones){ if (data[left++]==1 ){ count--; } } if (right-left==ones){ max=Math.max(max,count); } } return ones-max; }
992. Subarrays with K Different Integers https://leetcode.com/problems/subarrays-with-k-different-integers/discuss/523136/JavaC%2B%2BPython-Sliding-Window
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public int subarraysWithKDistinct (int [] nums, int k) { return atMostK(nums,k)-atMostK(nums,k-1 ); } int atMostK (int [] nums, int k) { int n=nums.length; int res=0 ; Map<Integer,Integer> map=new HashMap <>(); int l=0 ; for (int r = 0 ; r < n; r++) { if (map.getOrDefault(nums[r],0 )==0 ){ k--; } map.put(nums[r],map.getOrDefault(nums[r],0 )+1 ); while (k<0 ){ map.put(nums[l],map.get(nums[l])-1 ); if (map.get(nums[l])==0 ){ k++; } l++; } res+=r-l+1 ; } return res; }
1456. Maximum Number of Vowels in a Substring of Given Length 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public int maxVowels (String s, int k) { char [] chars=s.toCharArray(); int n=chars.length; int res=0 ; int l=0 ; int r=0 ; int count=0 ; while (r<n){ if (isVowel(chars[r])){ count++; } r++; if (r-l==k){ res=Math.max(res,count); if (isVowel(chars[l])){ count--; } l++; } } return res; } private boolean isVowel (char c) { return c=='a' || c=='e' || c=='i' || c=='o' || c=='u' ; }
2461. Maximum Sum of Distinct Subarrays With Length K 看到maximum/minimum subarray, 考虑sliding window
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public long maximumSubarraySum (int [] nums, int k) { int n=nums.length; Map<Integer,Integer> window=new HashMap <>(); int l=0 ; int r=0 ; long max=0 ; long sum=0 ; while (r<n){ sum+=nums[r]; window.put(nums[r],window.getOrDefault(nums[r],0 )+1 ); r++; while (r-l>k || window.get(nums[r-1 ])>1 ){ sum-=nums[l]; window.put(nums[l],window.get(nums[l])-1 ); l++; } if (r-l==k){ max=Math.max(max,sum); } } return max; }
2762. Continuous Subarrays 见Subarray, 思DP or Sliding Window
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public long continuousSubarrays (int [] nums) { long res=0 ; int l=0 ; int r=0 ; TreeMap<Integer,Integer> map=new TreeMap <>(); int n=nums.length; while (r<n){ map.put(nums[r],map.getOrDefault(nums[r],0 )+1 ); r++; int max=map.lastKey(); int min=map.firstKey(); while (max-nums[r-1 ]>2 || nums[r-1 ]-min>2 ){ int val=map.get(nums[l]); if (val==1 ){ map.remove(nums[l]); }else { map.put(nums[l],val-1 ); } l++; max=map.lastKey(); min=map.firstKey(); } res+=r-l; } return res; }
2747. Count Zero Request Servers 思路:遍历时考察值有进有出,考虑sliding window
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 vector<int > countServers (int n, vector<vector<int >>& logs, int x, vector<int >& queries) { int m = logs.size (); vector<pair<int ,int >> vp; for (auto it:logs) vp.push_back ({it[1 ],it[0 ]}); sort (vp.begin (),vp.end ()); int q = queries.size (); unordered_map<int ,int > mp; vector<int > ans (q,0 ) ; vector<pair<int ,int >> time (q); for (int i = 0 ;i<q;i++) time[i] = {queries[i],i}; sort (time.begin (),time.end ()); int i = 0 ,j = 0 ; for (auto tm:time) { int curtime = tm.first; int ind = tm.second; int start = max (0 ,curtime-x); int end = curtime; while (j<m and vp[j].first<=end) { mp[vp[j].second]++; j++; } while (i<m and vp[i].first<start) { if (mp[vp[i].second]==1 ) mp.erase (vp[i].second); else mp[vp[i].second]--; i++; } ans[ind] = n - mp.size (); } return ans; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public int [] countServers(int n, int [][] logs, int x, int [] queries) { int len=queries.length; int [] res=new int [len]; Arrays.sort(logs,(a,b)->(a[1 ]-b[1 ])); int [][] qs=new int [len][2 ]; for (int i = 0 ; i < len; i++) { qs[i][0 ]=i; qs[i][1 ]=queries[i]; } Arrays.sort(qs,(a,b)->(a[1 ]-b[1 ])); Map<Integer,Integer> map=new HashMap <>(); int l=logs.length; int left=0 ; int right=0 ; for (int i = 0 ; i < len; i++) { int idx=qs[i][0 ]; int t=qs[i][1 ]; int start= t-x>=0 ? t-x : 0 ; int end=t; while (right<l && logs[right][1 ]<=end){ map.put(logs[right][0 ],map.getOrDefault(logs[right][0 ],0 )+1 ); right++; } while (left<right && logs[left][1 ]<start){ int val=map.get(logs[left][0 ]); if (val==1 ){ map.remove(logs[left][0 ]); }else { map.put(logs[left][0 ],val-1 ); } left++; } res[idx]=n-map.size(); } return res; }