题目描述
给你一个字符串 s
、一个字符串 t
。返回 s
中涵盖 t
所有字符的最小子串。如果 s
中不存在涵盖 t
所有字符的子串,则返回空字符串 ""
。
注意:
- 对于
t
中重复字符,我们寻找的子字符串中该字符数量必须不少于 t
中该字符数量。
- 如果
s
中存在这样的子串,我们保证它是唯一的答案。
示例 1:
1 2
| 输入:s = "ADOBECODEBANC", t = "ABC" 输出:"BANC"
|
示例 2:
1 2
| 输入:s = "a", t = "a" 输出:"a"
|
示例 3:
1 2 3 4
| 输入: s = "a", t = "aa" 输出: "" 解释: t 中两个字符 'a' 均应包含在 s 的子串中, 因此没有符合条件的子字符串,返回空字符串。
|
提示:
1 <= s.length, t.length <= 10^5
s
和 t
由英文字母组成
进阶: 你能设计一个在 o(n)
时间内解决此问题的算法吗?
解法
滑动窗口
- 一个用于「延伸」现有窗口的 r指针
- 一个用于「收缩」窗口的 l指针
- 在任意时刻,只有一个指针运动,而另一个保持静止。我们在 s上滑动窗口,通过移动 r指针不断扩张窗口。
- 当窗口包含 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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| import java.util.HashMap; import java.util.Iterator; import java.util.Map;
class Solution { Map<Character, Integer> sMap = new HashMap<>(); Map<Character, Integer> tMap = new HashMap<>();
public String minWindow(String s, String t) { int tLen = t.length(); int sLen = s.length(); int ans_left = -1; int ans_right = -1; int ans_len = Integer.MAX_VALUE; int left = 0, right = -1; for (int i = 0; i < tLen; i++) { char c = t.charAt(i); tMap.put(c, tMap.getOrDefault(c, 0) + 1); } while (right < sLen) { right++; if (right < sLen && tMap.containsKey(s.charAt(right))) { char key = s.charAt(right); sMap.put(key, sMap.getOrDefault(key, 0) + 1); } while (check() && left <= right) { if (right - left + 1 < ans_len) { ans_len = right - left + 1; ans_left = left; ans_right = right + 1; } if (tMap.containsKey(s.charAt(left))) { Character key = s.charAt(left); sMap.put(key, sMap.getOrDefault(key, 0) - 1); } left++; } } return ans_left == -1 ? "" : s.substring(ans_left, ans_right); }
public boolean check() { for (Map.Entry<Character, Integer> tEntry : tMap.entrySet()) { Character key = tEntry.getKey(); Integer value = tEntry.getValue(); if (sMap.getOrDefault(key, 0) < value) { return false; } } return true; } }
|
来源:力扣(LeetCode)
链接:76. 最小覆盖子串 - 力扣(LeetCode)