滑动窗口
包含特定元素的子串(要匹配到的目标),或最长[这个好像没啥意思]、或最短、或等长
思考:(暂时感受)
1)什么时候扩充窗口——串没走完就得扩呀;
2)窗口扩充后要更新哪些东西——窗口包括的内容,毕竟新来人了,东西多了;
3)什么时候缩小窗口——得看目标条件是啥了,最短的情况吧只要目标条件够了就得收缩,等长的情况吧等长就得缩噻;
4)窗口缩小后要更新哪些东西——窗口包括的内容;
5)什么时候更新结果——收缩的时候,还是一轮结束的时候。
1. 最小覆盖子串 76 简单
class Solution {public String minWindow(String s, String t) {// 两个Map记录目标字符以及窗口包含的字符Map<Character, Integer> need = new HashMap<>();Map<Character, Integer> window = new HashMap<>();// 填充目标字符的Mapfor (char c: t.toCharArray()) {need.put(c, need.getOrDefault(c, 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) {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);}
}
2. 字符串的排列 567 中等
class Solution {public boolean checkInclusion(String s1, String s2) {// 思路:缩到最小覆盖,长度如果与s1相等,说明s1的排列之一是s2的子串// Map记录数量Map<Character, Integer> need = new HashMap<>();Map<Character, Integer> window = new HashMap<>();// 填充needfor (char c : s1.toCharArray()) {need.put(c, need.getOrDefault(c, 0) + 1);}// 滑动窗口int left = 0;int right = 0;// int start = 0;// int len = Integer.MAX_VALUE;int valid = 0;while (right < s2.length()) {char c = s2.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 >= s1.length()) {// while (valid == need.size()) {// if (right - left < len) {// start = left;// len = right - left;// }// 判断是否找到了合适的子串if (valid == need.size()) {return true;}char d = s2.charAt(left);left ++;if (need.containsKey(d)) {if (window.get(d).equals(need.get(d))) {valid --;}window.put(d, window.get(d) - 1);}} // if (len == s1.length()) {// return true;// }}return false;}
}
3. 找到字符串中所有字母异位词 438 中等
class Solution {public List<Integer> findAnagrams(String s, String p) {// 存放结果List<Integer> result = new ArrayList<>();// 存放窗口元素Map<Character, Integer> need = new HashMap<>();Map<Character, Integer> window = new HashMap<>();for (char c : p.toCharArray()) {need.put(c, need.getOrDefault(c, 0) + 1);}// 滑动窗口的左右指针int left = 0;int 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 (need.get(c).equals(window.get(c))) {valid ++;}}while (right - left >= p.length()) {if (valid == need.size()) {result.add(left);// // window和valid要清空// window.clear();// valid = 0;}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 result;}
}
4. 无重复字符的最长子串 3 中等
class Solution {public int lengthOfLongestSubstring(String s) {// 结果int result = 0;// 滑动窗口:重要的是如果map中键的值超过2,那就说明需要缩小窗口了Map<Character, Integer> window = new HashMap<>();int left = 0;int right = 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);}// 更新答案result = Math.max(result, right - left);}return result;}
}
【未完待续……】