由题还是很容易想到可以用一个哈希表来统计字符串中每个字符出现的次数。首先扫描字符串t,每扫到一个,哈希表中对应值加1。然后扫描字符串s,每扫描一个就检查哈希表中是否包含该字符,没有则忽略不计。如果存在,对应的值减1。所有如果字符串s包含字符串t的所有字符,那么哈希表中的所有的值应该都小于或等于0。
还是维护一个滑动窗口,某一时刻两指针间子字符串还没包含字符串t的所有字符,则移动右指针添加新的字符,如果还没有则继续移动右指针。
某一时刻两指针间子字符串已经包含字符串t的所有字符,因为目标是找出最短符合条件的子字符串,所有移动左指针,然后判断删除最左边的字符后是否仍包含字符串t的所有字符。
public String minWindow(String s, String t) {// 创建一个HashMap,用于存储字符串 t 中每个字符的出现次数// 因为用HashMap很方便判断一个字符是否在字符串t中出现// 所有没有用数组去模拟哈希表HashMap<Character, Integer> charToCount = new HashMap<>();// 遍历字符串 t,将每个字符及其出现次数存入HashMapfor (char ch : t.toCharArray()) {charToCount.put(ch, charToCount.getOrDefault(ch, 0) + 1);}// 初始化计数器,表示还需要找到的字符个数int count = charToCount.size();// 初始化左、右指针和最小窗口的起始和结束位置int start = 0, end = 0, minStart = 0, minEnd = 0;// 初始化最小窗口的长度为整数最大值int minLength = Integer.MAX_VALUE;// 开始遍历字符串 swhile (end < s.length() || (count == 0 && end == s.length())) {if (count > 0) {// 如果还有字符未找到// 取得当前指针处的字符char endCh = s.charAt(end);// 如果该字符在字符串 t 中存在if (charToCount.containsKey(endCh)) {// 更新HashMap中该字符的出现次数charToCount.put(endCh, charToCount.get(endCh) - 1);// 如果出现次数减至零,表示该字符已找到足够次数if (charToCount.get(endCh) == 0) {count--;}}// 移动指针end++;} else {// 如果所有字符都已找到// 计算当前窗口的长度if (end - start < minLength) {minLength = end - start;minStart = start;minEnd = end;}// 取得当前指针处的字符char startCh = s.charAt(start);// 如果该字符在字符串 t 中存在if (charToCount.containsKey(startCh)) {// 更新HashMap中该字符的出现次数charToCount.put(startCh, charToCount.get(startCh) + 1);// 如果出现次数增至1,表示还需要找到该字符if (charToCount.get(startCh) == 1) {count++;}}// 移动指针start++;}}// 返回最小窗口子串,如果没有找到则返回空字符串return minLength < Integer.MAX_VALUE ? s.substring(minStart, minEnd) : "";}
下面是对代码的一个详细解释(因为是Hard难度所以再借助AI全面阐述一遍)
-
初始化HashMap: 代码一开始创建了一个HashMap
charToCount
,用于存储字符串t
中每个字符的出现次数。 -
遍历字符串
t
: 程序首先遍历字符串t
,将其中每个字符及其出现的次数存储在charToCount
中。 -
初始化变量: 初始化了一些变量,包括计数器
count
(表示还需要找到的字符个数)、指针start
和end
(用于构建窗口)、以及用于记录最小窗口的起始和结束位置的变量minStart
和minEnd
,同时也初始化了记录最小窗口长度的变量minLength
为整数最大值。 -
使用滑动窗口算法: 在这段代码中,通过滑动窗口算法来寻找符合条件的最小窗口子串。
-
遍历字符串
s
: 使用while
循环遍历字符串s
,其中end
指针不断向右移动。 -
找到包含
t
中所有字符的窗口:- 当
count > 0
时,表示还有字符未找到。程序会检查当前end
指向的字符是否在字符串t
中,如果是,更新该字符在charToCount
中的计数,当某个字符的计数减为零时,count
减一,表示找到了一个字符。 - 一旦
count
减至零(意味着已经找到了所有t
中的字符),代码会执行else
部分,这时会计算当前窗口的长度,并与之前记录的最小长度进行比较。 - 如果当前窗口的长度更小,则更新最小长度
minLength
,同时记录当前窗口的起始和结束位置minStart
和minEnd
。 start
指针向右移动,并且对应字符在charToCount
中的计数也会相应地更新,直到count
不再为零。
- 当
-
返回结果: 最后,根据
minLength
是否被更新过来判断是否找到了包含t
中所有字符的最小窗口子串。如果找到了,返回该子串;否则返回空字符串。