滑动窗口-Substring Search Problem
2018-07-18 11:19:19
一、Minimum Window Substring
问题描述:
问题求解:
public String minWindow(String s, String t) { String res = ""; if (t.length() > s.length()) return res; Map<Character, Integer> map = new HashMap<>(); for (int i = 0; i < t.length(); i++) { map.put(t.charAt(i), map.getOrDefault(t.charAt(i), 0) + 1); } int begin, end, count; begin = 0; end = 0; count = map.size(); int minLen = Integer.MAX_VALUE; for (; end < s.length(); end++) { char c = s.charAt(end); if (map.containsKey(c)) { map.put(c, map.get(c) - 1); if (map.get(c) == 0) count--; } while (count == 0) { if (end - begin + 1 < minLen) { res = s.substring(begin, end); minLen = end - begin + 1; } char temp = s.charAt(begin); if (map.containsKey(temp)) { if (map.get(temp) == 0) count++; map.put(temp, map.get(temp) + 1); } begin++; } } return res; }
二、Longest Substring Without Repeating Characters
问题描述:
问题求解:
public int lengthOfLongestSubstring(String s) { int[] map = new int[256]; int res = 0; int begin = 0; for (int end = 0; end < s.length(); end++) { char c = s.charAt(end); map[c]++; while (map[c] > 1) { map[s.charAt(begin)]--; begin++; } res = Math.max(res, end - begin + 1); } return res; }
三、Substring with Concatenation of All Words
问题描述:
问题求解:
本题其实是一道拓展题,这里题目中给出了所有单词的长度相同,也就意味着可以将所有的单词看作单个字母来进行处理,如果是这样的话,那么外层循环很显然就是word length了。之后通过两个Map对单词进行计数就可以进行解决。
public List<Integer> findSubstring(String s, String[] words) { List<Integer> res = new ArrayList<>(); if (s == null || s.length() == 0 || words.length == 0) return res; Map<String, Integer> map = new HashMap<>(); int wl = words[0].length(); int num = words.length; int n = s.length(); if (n < num * wl) return res; for (int i = 0; i < num; i++) map.put(words[i], map.getOrDefault(words[i], 0) + 1); for (int i = 0; i < wl; i++) { int begin, end, cnt; Map<String, Integer> seen = new HashMap<>(); begin = i; cnt = 0; for (end = begin; end <= n - wl; end += wl) { String str = s.substring(end, end + wl); // 匹配成功 if (map.containsKey(str)) { seen.put(str, seen.getOrDefault(str, 0) + 1); cnt++; // 若计数个数超过map, 则需要对窗口大小进行调整 while (seen.get(str) > map.get(str)) { String temp = s.substring(begin, begin + wl); seen.put(temp, seen.get(temp) - 1); begin = begin + wl; cnt--; } // 如果所有单词都匹配完成, 则向res中添加答案,同时将窗口大小向前挪动一步 if (cnt == num) { res.add(begin); String temp = s.substring(begin, begin + wl); seen.put(temp, seen.get(temp) - 1); begin = begin + wl; cnt--; } } // 当前匹配失败,则begin要从下一个开始,且所有的计数都要初始化 else { seen.clear(); begin = end + wl; cnt = 0; } } } return res; }
四、Longest Substring with At Least K Repeating Characters
问题描述:
问题求解:
单纯的使用滑动窗口在修改窗口大小的时候会出现难以判断的情况,可以引入uniqueNum这个变量,来表征K个不同的字母,这样就可以大大降低问题的复杂度。
public int longestSubstring(String s, int k) { int res = 0; char[] chs = s.toCharArray(); for (int i = 1; i <= 26; i++) { res = Math.max(res, helper(chs, k, i)); } return res; } private int helper(char[] chs, int k, int uniqueNum) { int res = 0; int[] cnt = new int[256]; int begin = 0; int nolessthank = 0; int curUnique = 0; for (int end = 0; end < chs.length; end++) { if (cnt[chs[end]] == 0) curUnique++; if (cnt[chs[end]] == k - 1) nolessthank++; cnt[chs[end]]++; while (curUnique > uniqueNum) { if (cnt[chs[begin]] == k) nolessthank--; if (cnt[chs[begin]] == 1) curUnique--; cnt[chs[begin]]--; begin++; } if (curUnique == uniqueNum && nolessthank == curUnique) res = Math.max(res, end - begin + 1); } return res; }
五、Max Consecutive Ones III
问题描述:
问题求解:
这种问题一般要么dp,要么滑动窗口,这种敏感性要有。
本题就是使用滑动窗口来进行解决的问题。实质上就是求解最长的substring其中至多包含k个0。
public int longestOnes(int[] A, int K) { int res = 0; int begin = 0; int cnt = 0; for (int end = 0; end < A.length; end++) { if (A[end] == 0) cnt+= 1; while (cnt > K) { if (A[begin] == 0) cnt -= 1; begin++; } res = Math.max(res, end - begin + 1); } return res; }