滑动窗口框架
滑动窗口就是简单维护一个窗口,不断滑动,然后更新答案,代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13
| int left = 0, right = 0;
while (right < nums.size()) { window.addLast(nums[right]); right++; while (window needs shrink) { window.removeFirst(nums[left]); left++; } }
|
滑动窗口的伪框架实现
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
| void slidingWindow(String s) { Object window = ... int left = 0, right = 0; while (right < s.length()) { char c = s[right]; window.add(c) right++; ...
printf("window: [%d, %d)\n", left, right);
while (left < right && window needs shrink) { char d = s[left]; window.remove(d) left++; ... } } }
|
基于滑动窗口实现的代码,时间复杂度是O(N)。
LeetCode76.最小覆盖子串
滑动窗口实现的简单思路:
1.在字符串s中使用双指针中的左右指针技巧,初始化left=right=0,将索引左闭右开区间[left,right)称为一个窗口。
2.不断增大right指针扩大窗口,[left,right),直至窗口中字符串符合要求。
3.此时,停止增加right,转而不断增大left缩小窗口[left,right),直至窗口中字符串不再符合要求。同时,每次增加left,都更新结果。
4.重复第二、三步,直至left到达s末尾。
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
| class Solution { public String minWindow(String s, String t) { Map<Character, Integer> need = new HashMap<>(); Map<Character, Integer> window = new HashMap<>(); for (char c : t.toCharArray()) { need.put(c, need.getOrDefault(c, 0) + 1); }
int left = 0, right = 0; int valid = 0; int start = 0, 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) { start = left; len = right - 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); } }
|
LeetCode 567.字符串排列
滑动窗口典型:给你一个 S 和一个 T,请问你 S 中是否存在一个子串,包含 T 中所有字符且不包含其他字符?
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
| class Solution { public boolean checkInclusion(String t, String s) { Map<Character, Integer> need = new HashMap<>(); Map<Character, Integer> window = new HashMap<>(); for (char c : t.toCharArray()) { need.put(c, need.getOrDefault(c, 0) + 1); }
int left = 0, right = 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 (window.get(c).intValue() == need.get(c).intValue()) valid++; }
while (right - left >= t.length()) { if (valid == need.size()) return true; char d = s.charAt(left); left++; if (need.containsKey(d)) { if (window.get(d).intValue() == need.get(d).intValue()) valid--; window.put(d, window.get(d) - 1); } } } return false; } }
|
LeetCode 438.找到字符串中所有字母异位词
相当于,输入一个串 S,一个串 T,找到 S 中所有 T 的排列,返回它们的起始索引。
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
| class Solution { public List<Integer> findAnagrams(String s, String t) { Map<Character, Integer> need = new HashMap<>(); Map<Character, Integer> window = new HashMap<>(); for (char c : t.toCharArray()) { need.put(c, need.getOrDefault(c, 0) + 1); }
int left = 0, right = 0; int valid = 0; List<Integer> res = new ArrayList<>(); 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 (right - left >= t.length()) { if (valid == need.size()) res.add(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 res; } }
|
LeetCode 3.最长无重复子串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Solution { public int lengthOfLongestSubstring(String s) { Map<Character, Integer> window = new HashMap<>(); int left = 0, right = 0; int res = 0; while (right < s.length()) { char c = s.charAt(right); right++; window.put(c, window.getOrDefault(c, 0) + 1); while (window.get(c) > 1) { char d = s.charAt(left); left++; window.put(d, window.get(d) - 1); } res = Math.max(res, right - left); } return res; } }
|