给定一个字符串S和一个字符串T,求S中的最小的窗口,其中包含了T中的字符。算法的复杂度为O(n)。
例如,S="ADOBECODEBANC", T="ABC"。最小的窗口是“BANC”。注意如果不存在覆盖了T中的所有的字符的窗口,返回空字符串。如果有多个这样的窗口,确保S中总有一个唯一的最小窗口。
package com.algo.coding.puzzles;
import java.util.HashMap;
public class MinWindow64 {
public String minWin(String resource, String target){
HashMap expectCountHs = new HashMap();
HashMap appearCountHs = new HashMap();
int minV = Integer.MAX_VALUE;
int start = 0;
int end = 0;
int winStart = 0;
for(int i = 0; i < target.length(); i++){
char c = target.charAt(i);
Object countObj = expectCountHs.get(c);
int count;
if(countObj != null){
count = (int) countObj;
count ++;
}else{
count = 1;
}
expectCountHs.put(target.charAt(i), count);
}
int appearChars = 0;
for(int winEnd = 0; winEnd < resource.length(); winEnd++){
char c = resource.charAt(winEnd);
int expectCount = this.getCount(expectCountHs, c);
/*
* only关心Target里有的字符
*/
if(expectCount > 0){
int appearCount = this.getCount(appearCountHs, c);
appearCount++;
appearCountHs.put(c, appearCount);
/*
* 当出现了期待的字符,会计算期待字符的个数。
*/
if(expectCount >= appearCount){
appearChars++;
}
}
/*
* appearCountHs 代表win start 和 win end 区间内字符串出现的次数。
* (在target里有的字符会比较存在的次数和target里的次数,严格等于appearCountHs。 在target里没有的字符,有可能出现-1,这不影响。)
* appearCountHs (A=1 B=1 C=1), expectCountHs (A=1 B=1 C=1), winStart = 0, winEnd = 5 没有运行 while
* appearCountHs (A=2 B=2 C=1), expectCountHs (A=1 B=1 C=1), winStart = 0, winEnd = 10 运行完下面的while,变成 winStart = 5, winEnd = 10
* appearCountHs (A=1 B=1 C=2), expectCountHs (A=1 B=1 C=1), winStart = 5, winEnd = 12
* 当C的appearCount > expectCount, winStart ++, 其他字符expectCount == 0 运行完下面的while,变成 winStart = 9, winEnd = 12
* */
char startChar = resource.charAt(winStart);
int startAppearCount = this.getCount(appearCountHs, startChar);
int startExpectCount = this.getCount(expectCountHs, startChar);
/*
* 当期待区间内出现所有期待的字符,才运行。去掉这个条件,minV最小会是1。
*/
if(appearChars == target.length()){
while(startAppearCount > startExpectCount || startExpectCount == 0){
startAppearCount --;
appearCountHs.put(startChar, startAppearCount);
winStart ++;
startChar = resource.charAt(winStart);
startAppearCount = this.getCount(appearCountHs, startChar);
startExpectCount = this.getCount(expectCountHs, startChar);
}
if(minV > winEnd - winStart + 1){
minV = winEnd - winStart + 1;
start = winStart;
end = winEnd;
}
// return resource.substring(start, end);
}
}
return resource.substring(start, end+1);
}
public int getCount(HashMap hs, char c){
Object obj = hs.get(c);
int count = 0;
if(obj != null){
count = (int) obj;
// count ++;
}
return count;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
// String resource = "ADOBECODEBANC";
// String target = "ABC";
// String resource = "abccbaddac";
// String target = "abcd";
String resource = "aabcadbbbcca";
String target = "abcd";
MinWindow64 minWin = new MinWindow64();
System.out.println(minWin.minWin(resource, target));;
}
}