https://leetcode.com/problems/minimum-window-substring/
给定两个字符串s和t,求出一个s中的最小子串,是这个子串包含t中的所有字符
例子:s="ADOBECODEBANC" t="ABC"
public String minWindow(String s, String t) {
String res = "";
HashMap<Character, Integer> letterCnt = new HashMap<Character, Integer>();
int left = 0, cnt = 0, minLen = Integer.MAX_VALUE;
//计算t中char的个数,并存入HashMap letterCnt
for (int i = 0; i < t.length(); i++) {
if (letterCnt.containsKey(t.charAt(i))) {
letterCnt.put(t.charAt(i), letterCnt.get(t.charAt(i)) + 1);
} else {
letterCnt.put(t.charAt(i), 1);
}
}
for (int i = 0; i < s.length(); i++) {
char tmp = s.charAt(i);
if (!letterCnt.containsKey(s.charAt(i))) {
continue;
}
//letterCnt中包含是该char,才继续往下走
letterCnt.put(tmp, letterCnt.get(tmp) - 1);
if (letterCnt.get(tmp) >= 0) {
cnt++;
}
//解释:当cnt达到了t的长度,left和i中间夹的这个子串一定包含t,
while (cnt == t.length()) {
char tmp1 = s.charAt(left);
//此时又分两种情况,
// 情况一:
// left的是在letterCnt中的:此时要做一波判断,i和left的中间子集是否是最小集
// (可以断定,最小集的时候,left对应的的值一定在letterCnt中)
if (letterCnt.containsKey(tmp1)) {
if (minLen > i - left + 1) {
minLen = i - left + 1;
res = s.substring(left, minLen + left);
}
//这句话有点意思,这句话是为了中和left++
//因为此时left在letterCnt中已经存在了,而这段代码往下执行,left一定会往右滑一个
//滑完之后,letterCnt中就少了一个tmp1,所以这里先加上
letterCnt.put(tmp1, letterCnt.get(tmp1) + 1);
//小tips letterCnt的值有可能为负,但是不影响结果~
//这段代码翻译就是,我即将右滑(left++),滑掉的这个字符,刚好是匹配上的,所以cnt要减1
//talk is cheap ,例子:
//s=ADOBECODEBANC,t=ABC
//当left=0,i=5的时候,res为"ADOBEC",这是下次要把第一个A滑走了~
// 所以到这里的时候letterCnt['A'] = 1(因为上一步+1了),所以当下一步left++后,相当于i和left之间没有A了~
//所以cnt要减1
if (letterCnt.get(tmp1) > 0) {
//当letterCnt里面还有这个字符的时候,表明还有未匹配的char(还需要在t中找相关的char)
cnt--;
}
}
// 情况二:left不在letterCnt中,所以不用判断,最小集的更改,因为此时一定不是最小集
// (you ask me why? I tell you think about it yourself)此时用left直接向右边滑动
//所以不管left在不在letterCnt中,left都要向右滑
left++;//flag1
}
}
return res;
}
网友评论