题目链接:https://leetcode.cn/problems/minimum-window-substring/
思路:使用一个needmap记录target中字符的数量,然后用一个windowmap开始收集字符串s中的字符,当条件满足时,就可以开始缩小滑动窗口,并在过程中记录最小子串长度,条件不满足了就退出缩小,继续扩大窗口,以此往复。
class Solution {
public String minWindow(String s, String t) {
Map<Character, Integer> window = new HashMap<>();
Map<Character, Integer> need = new HashMap<>();
for (char c : t.toCharArray()) {
need.put(c, need.getOrDefault(c, 0) + 1);
}
int left = 0, right = 0, valid = 0, init = 0;
int min = Integer.MAX_VALUE;
while (right < s.length()) {
char rc = s.charAt(right);
right++;
if (need.containsKey(rc)) {
window.put(rc, window.getOrDefault(rc, 0) + 1);
if (window.get(rc).equals(need.get(rc))) {
valid++;
}
}
while (valid == need.size()) {
if (right - left < min) {
min = right - left;
init = left;
}
char lc = s.charAt(left);
left++;
if (need.containsKey(lc)) {
if (need.get(lc).equals(window.get(lc))) {
valid--;
}
window.put(lc, window.get(lc)-1);
}
}
}
return min == Integer.MAX_VALUE ? "" : s.substring(init, init+min);
}
}
题目链接:https://leetcode.cn/problems/permutation-in-string/
思路:一样是滑动窗口,要求s1的排列是否包含在s2中,其实滑动窗口只要维持和s1的长度相等即可,然后判断这个窗口内元素的个数是否满足。
class Solution {
public boolean checkInclusion(String s1, String s2) {
Map<Character, Integer> need = new HashMap<>();
Map<Character, Integer> window = new HashMap<>();
for (char c : s1.toCharArray()) {
need.put(c, need.getOrDefault(c, 0)+1);
}
int left = 0, right = 0, valid = 0;
while (right < s2.length()) {
char rc = s2.charAt(right);
right++;
if (need.containsKey(rc)) {
window.put(rc, window.getOrDefault(rc, 0)+1);
if (window.get(rc).equals(need.get(rc))) {
valid++;
}
}
if (right - left == s1.length()) {
if (valid == need.size()) return true;
char lc = s2.charAt(left);
left++;
if (need.containsKey(lc)) {
if (need.get(lc).equals(window.get(lc))) {
valid--;
}
window.put(lc, window.get(lc)-1);
}
}
}
return false;
}
}
题目链接:https://leetcode.cn/problems/find-all-anagrams-in-a-string/
思路:也是滑动窗口,这个找异位词和上一题很类似,只不过上一题就一个,这题是有多个然后收集起始位置。
class Solution {
public List<Integer> findAnagrams(String s, String p) {
List<Integer> list = 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, right = 0, valid = 0;
while (right < s.length()) {
char rc = s.charAt(right);
right++;
if (need.containsKey(rc)) {
window.put(rc, window.getOrDefault(rc, 0)+1);
if (window.get(rc).equals(need.get(rc))) {
valid++;
}
}
if (right - left == p.length()) {
if (valid == need.size()) {
list.add(left);
}
char lc = s.charAt(left);
left++;
if (need.containsKey(lc)) {
if (window.get(lc).equals(need.get(lc))) {
valid--;
}
window.put(lc, window.get(lc)-1);
}
}
}
return list;
}
}
题目链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters/
思路:求无重复字符的最长子串,扩大窗口时只需要一直往里放即可,如果当前元素添加后数量大于1,就要开始收缩窗口,直到当前元素个数不再大于1,期间窗口每扩大一步就更新一次最大值。
class Solution {
public int lengthOfLongestSubstring(String s) {
Map<Character, Integer> window = new HashMap<>();
int left = 0, right = 0;
int max = 0;
while (right < s.length()) {
char rc = s.charAt(right);
right++;
window.put(rc, window.getOrDefault(rc, 0)+1);
while (window.get(rc) > 1) {
char lc = s.charAt(left);
left++;
window.put(lc, window.get(lc)-1);
}
max = Math.max(max, right-left);
}
return max;
}
}