题目
给定字符串s,字符串t,查找字符串s中包含字符串t中全部字符的最短子串
解题
通过滑动窗口来计算字符串s中包含字符串t的窗口,并按需调整窗口大小,取最小窗口大小返回
private static String findMinStringContainTarget(String source, String target) {
if (StringUtils.isEmpty(source) || StringUtils.isEmpty(target) || source.length() < target.length()) {
return "";
}
//记一下字符串t中每个字符及其数量
Map<Character, Integer> targetCharCount = new HashMap<>();
for (char item : target.toCharArray()) {
Integer curCount = targetCharCount.getOrDefault(item, 0);
targetCharCount.put(item, curCount + 1);
}
int sourceLength = source.length();
int leftIndex = 0;
int rightIndex = target.length() - 1;
//记录最小覆盖字符串的两端下标
int minLenLeftIndex = 0;
int minLenRightIndex = sourceLength;
boolean hasContain = false;
while (rightIndex < sourceLength) {
//记录下字符串s中在leftIndex到rightIndex之间的字符数
Map<Character, Integer> rangeContains = new HashMap<>();
for (int i = leftIndex; i <= rightIndex; i++) {
Integer curCount = rangeContains.getOrDefault(source.charAt(i), 0);
rangeContains.put(source.charAt(i), curCount + 1);
}
//判断子字符串中是否包含了字符串t中所有字符及其数量
Iterator<Map.Entry<Character, Integer>> iterator = targetCharCount.entrySet().iterator();
boolean contain = true;
while (iterator.hasNext()) {
Map.Entry<Character, Integer> next = iterator.next();
if (!rangeContains.containsKey(next.getKey()) || rangeContains.get(next.getKey()) < next.getValue()) {
contain = false;
break;
}
}
if (contain) {
//当前子字符串包含了字符串t中的所有字符,则左边界右移
if (minLenRightIndex - minLenLeftIndex > rightIndex - leftIndex) {
minLenLeftIndex = leftIndex;
minLenRightIndex = rightIndex;
hasContain=true;
}
leftIndex++;
} else {
//当前子字符串不包含字符串t中的所有字符,则应该扩展子字符串,右边界右移
rightIndex++;
//右移时如果移动的字符不在字符串t的范围内,则继续右移
while (rightIndex < sourceLength && !targetCharCount.containsKey(source.charAt(rightIndex))) {
rightIndex++;
}
}
}
//表示两个字符串包含相同的字符
if (hasContain&&minLenRightIndex == sourceLength) {
return source.substring(minLenLeftIndex);
}
//表示字符串s不存在字符串包含字符串t
if (minLenRightIndex == sourceLength) {
return "";
}
return source.substring(minLenLeftIndex, minLenRightIndex + 1);
}