题目
给定一个字符串 S 和一个字符串 T,请在 S 中找出包含 T 所有字母的最小子串。
示例:
输入: S = “ADOBECODEBANC”, T = “ABC”
输出: “BANC”
说明:
如果 S 中不存这样的子串,则返回空字符串 “”。
如果 S 中存在这样的子串,我们保证它是唯一的答案。
解答
个人想到的是使用滑动窗口来解答, 好像性能不是很好,代码如下:
import java.util.HashMap;
class Solution {
public String minWindow(String s, String t) {
// 分别用于记录目标最小子串的左边界和右边界
int resultLeft = 0, resultRight = -1;
int minLength = s.length() + 1;
// 用于记录子串的左右边界
int left = 0, right = -1;
// 用于记录包含的字母个数
int count = 0;
HashMap<Character, Integer> map = new HashMap<>();
char[] charc = t.toCharArray();
for (char aChar : charc) {
map.put(aChar, map.containsKey(aChar) ? map.get(aChar) + 1 : 1);
}
char[] chars = s.toCharArray();
while (right < s.length() && left < s.length()){
if (count == t.length()){
if (minLength > right - left){
minLength = right - left;
resultLeft = left;
resultRight = right;
}
if (map.containsKey(chars[left])){
if (map.get(chars[left]) == 0){
count--;
}
map.put(chars[left], map.get(chars[left]) + 1);
}
left++;
} else {
right++;
if (right >= s.length()) {
break;
}
if (map.containsKey(chars[right])){
if (map.get(chars[right]) > 0) {
count++;
}
map.put(chars[right], map.get(chars[right]) - 1);
}
}
}
if(resultLeft == 0 && resultRight == -1){
return "";
}
return s.substring(resultLeft, resultRight + 1);
}
}
下面也贴一下LeetCode上用时最短的解答:
class Solution {
public String minWindow(String s, String t) {
int[] count = new int['z' - 'A' + 1];
int uniq = 0;
for (int i = 0; i < t.length(); ++i) {
if (++count[t.charAt(i) - 'A'] == 1) {
uniq++;
}
}
// expand
int found = 0;
int i = 0;
int j = 0;
int minLen = Integer.MAX_VALUE;
int minJ = Integer.MAX_VALUE;
while (found < uniq) {
while (i < s.length()) {
if (found >= uniq) {
break;
}
if (--count[s.charAt(i) - 'A'] == 0) {
found++;
}
i++;
}
if (found < uniq) {
break;
}
// shorten
while (j < i && count[s.charAt(j) - 'A'] < 0) {
count[s.charAt(j++) - 'A']++;
}
if (i - j < minLen) {
minLen = i - j;
minJ = j;
}
count[s.charAt(j++) - 'A']++;
found--;
}
if (minLen < Integer.MAX_VALUE) {
return s.substring(minJ, minJ + minLen);
}
return "";
}
}