LeetCode 76.最小覆盖字串 | 滑动窗口 | 解题思路及代码
最小覆盖字串
原题: 76. Minimum Window Substring
题目描述:
给定两个字符串,s
和t
,求s
的最短子字符串,使其包含t
中的所有字符(包含重复的)。
思路:
滑动窗口
先使用 Map ori
统计t
中所有的字符及其个数,用另外一个 Map cnt
统计目前滑动窗口中出现的t
中字符的个数。还有一个数count
记录cnt
中还需要的字符个数。对于每个字符来说,它在cnt
中的频率可能会高于ori
,如果大于ori
中对应的频率,那么我们只算ori
中出现的频率。
使用左右双指针,右指针从左到右扫描,如果右指针指向的字符在t
中出现,那么把cnt
中对应的字符频率加一。如果出现并且出现的次数小于ori
(也就是应该出现的次数),那就说明这个滑动窗口中的目标字符++,我们把count
减少1。
如果count=0
,那就说明现在的滑动窗口包含了所有的目标字符(及重复)。现在开始把左指针向右移动。每次移动检测指向的值是否在ori
中,若在,并且cnt
中的值大于ori
中的值,说明该字符的频率比所需的频率高,将其频率--,继续右移左指针。如果不在ori
中,那就是无关字符,直接右移左指针。
直到左指针指向的值在cnt
中的频率等于ori
中的频率,此时我们把其cnt
中的频率-1。这时的滑动窗口包含了所有字符的对应频率,并且窗口的左右都没有冗余字符。如果窗口长度小于目前所遇到的最小长度,则更新记录左右指针的位置。最后右移一次左指针,开始下一轮循环。
直到右指针的位置等于s
的长度了,说明窗口滑动完了。如果有符合要求的窗口被记录下来。返回对应的子字符串,否则返回""
。
代码:
Java
import java.util.HashMap;
import java.util.Map;
class Solution {
Map<Character, Integer> ori = new HashMap<Character, Integer>();
Map<Character, Integer> cnt = new HashMap<Character, Integer>();
public String minWindow(String s, String t) {
int sLen = s.length(), tLen = t.length();
int l = 0, r = -1, count = tLen;
int len = Integer.MAX_VALUE, ansL = -1, ansR = -1;
for (int i = 0; i < tLen; i++) {
char c = t.charAt(i);
ori.put(c, ori.getOrDefault(c, 0) + 1);
}
while (r < sLen) {
r++;
if (r < sLen && count != 0 && ori.containsKey(s.charAt(r))) {
if (cnt.getOrDefault(s.charAt(r), 0) < ori.get(s.charAt(r))) {
count--;
}
cnt.put(s.charAt(r), cnt.getOrDefault(s.charAt(r), 0) + 1);
}
if (count == 0 && r < sLen) {
while (true) {
if (cnt.getOrDefault(s.charAt(l), 0) == 0) {
l++;
} else if (cnt.get(s.charAt(l)) > ori.get(s.charAt(l))) {
cnt.put(s.charAt(l), cnt.get(s.charAt(l)) - 1);
l++;
} else {
break;
}
}
cnt.put(s.charAt(l), cnt.get(s.charAt(l)) - 1);
count++;
if (r - l < len) {
len = r - l;
ansL = l;
ansR = r+1;
}
l++;
}
}
return ansL == -1 ? "" : s.substring(ansL, ansR);
}
}