给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。
注意:如果 s 中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
示例 2:
输入:s = "a", t = "a"
输出:"a"
提示:
1 <= s.length, t.length <= 10^5
s 和 t 由英文字母组成
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-window-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
---------------------------------------------------------------------------------------------------------------------------
这道题目采用滑动窗口的解法相对会简单点:
①统计字符串t 中字符出现的次数(因为只需要包含,不需要按顺序,所以比较个数是比较简单的做法),以及窗口中字符出现的次数
②用count来记录在窗口中找到了满足了条件的字符的个数,当count与target的大小相等时,证明此时的窗口包含了t中出现的所有字符
③当当前窗口已经覆盖了字符串t,则开始向右移动左指针,即移除最左边的字符
此时,如果最左边的字符是t中出现的字符,则判断此字符的个数是否恰好等于其在t中出现的次数(可能会大于),如果恰好等于,移除了之后,则代表此字符未满足条件,所以要将count的量减一,同时要更新窗口中此字符出现的次数。
完整代码如下:
public String minWindow(String s, String t) { //统计窗口中字符出现的个数以及t中字符出现的个数 Map<Character, Integer> window = new HashMap<>(); Map<Character, Integer> target = new HashMap<>(); for (char c : t.toCharArray()){ target.put(c, target.getOrDefault(c, 0)+1); } char[] chars = s.toCharArray(); int left = 0, right = 0; //左右指针 int count = 0, minLen = Integer.MAX_VALUE, start = 0; //满足条件的字符个数,符合要求的字符串的最小长度, 符合要求的字符串的起始位置 while (right < chars.length){ if (target.containsKey(chars[right])){ window.put(chars[right], window.getOrDefault(chars[right],0)+1); if (window.get(chars[right]).equals(target.get(chars[right]))){ count++; } } while (count == target.size()){ if (right-left+1 < minLen){ minLen = right-left+1; start = left; } //开始往右移动左指针 char c = chars[left++]; if (target.containsKey(c)){ if (window.get(c).equals(target.get(c))){ count--; } window.put(c, window.getOrDefault(c,0)-1); } } right++; } return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start+minLen); }