0076. Minimum Window Substring - kumaeki/LeetCode GitHub Wiki
0076. Minimum Window Substring
Given two strings s and t of lengths m and n respectively, return the minimum window substring of s such that every character in t (including duplicates) is included in the window.
If there is no such substring, return the empty string "".
The testcases will be generated such that the answer is unique.
A substring is a contiguous sequence of characters within the string.
Example 1:
Input: s = "ADOBECODEBANC", t = "ABC"
Output: "BANC"
Explanation: The minimum window substring "BANC" includes 'A', 'B', and 'C' from string t.
Example 2:
Input: s = "a", t = "a"
Output: "a"
Explanation: The entire string s is the minimum window.
Example 3:
Input: s = "a", t = "aa"
Output: ""
Explanation: Both 'a's from t must be included in the window.
Since the largest window of s only has one 'a', return empty string.
Constraints:
- m == s.length
- n == t.length
- 1 <= m, n <= 10^5
- s and t consist of uppercase and lowercase English letters.
解法1
滑动窗口.
class Solution {
public String minWindow(String s, String t) {
// 用map来保存字符串t中含有的字符, 以及数量
Map<Character, Integer> map = new HashMap<Character, Integer>();
for(char c : t.toCharArray())
map.put(c, map.getOrDefault(c, 0) + 1);
// t中含有的字符的个数
int charNums = map.size();
// 用caMap来保存滑动窗口中含有的字符,以及数量
Map<Character, Integer> caMap = new HashMap<Character, Integer>();
// 最终结果的窗口长度, 左边界和右边界
int res = -1 , rl = 0, rr = 0;
// 滑动窗口的左边界和右边界
int left = 0, right = 0;
int len = s.length();
// 滑动窗口中含有的满足条件的字符的个数(条件为, 该字符的数量和t中该字符的数量一致)
int caCharNums = 0;
while(right < len){
// 右边界
char c = s.charAt(right);
// 如果map中包含c
if(map.containsKey(c)){
caMap.put(c, caMap.getOrDefault(c, 0) + 1);
// 如果c在map和caMap中的数量一致(在当前窗口中,c字符的数量一致)
// 那么滑动窗口中一直的字符的个数加1
if(map.get(c).intValue() == caMap.get(c).intValue())
caCharNums++;
// 在滑动窗口包含了t中的所有字符时, 尝试移动左边界来缩短窗口长度
while(caCharNums == charNums){
char cl = s.charAt(left);
// 如果左边界的字符在map中有, 那么开始计算
// 其实当前滑动窗口的长度在无效字符(左边界在map中不存在)时也可以计算
// 但是只在碰到有效字符时才计算可以减少计算次数.
if(map.containsKey(cl)){
// 如果这是第一次得到满足条件的滑动窗口,或者这一次比上一次的窗口长度小
// 更新最终结果
if(res == -1 || right - left + 1 < res){
res = right - left + 1;
rl = left;
rr = right;
}
// 当前左边界对应的字符的数量减1
caMap.put(cl, caMap.get(cl)-1);
// 如果字符数量小于map中该字符的数量,
if(map.get(cl).intValue() > caMap.get(cl).intValue())
caCharNums--;
}
// 窗口左边界向右移动
left++;
}
}
// 窗口右边界向右移动
right++;
}
return res == -1 ? "" : s.substring(rl, rr + 1);
}
}