题目链接:76. 最小覆盖子串 - 力扣(LeetCode)
1.暴力解法(会超时)
题目意思为在s中找到一个最短的子串,这个子串要求要包含t中所有的字符;
可以用一个数组tArr存下t中每个字符的个数,用count表示有效字符的个数;
遍历s,将s中的字ch存入数组sArr中,若sArr[ch] <= tArr[ch],则说明ch是一个有效字符,将count++;当count与t的长度相等时,就说明此时s的子串符合条件,记下子串长度与开始下标,继续遍历,找到最短的子串,代码如下:
public String minWindow(String s, String t) {
int sLen = s.length();
int tLen = t.length();
int[] tArr = new int[128];
int min = sLen + 1;
int index = 0;
for (int i = 0; i < tLen; i++) {
char ch = t.charAt(i);
tArr[ch]++;
}
for (int i = 0; i < sLen; i++) {
int[] sArr = new int[128];
int count = 0;//记录是不是有效字符
for (int j = i; j < sLen; j++) {
char ch = s.charAt(j);
sArr[ch]++;
if (sArr[ch] <= tArr[ch]) {
count++;//是有效字符
}
if (count == tLen) {
if (min > j - i + 1) {
min = j - i + 1;
index = i;//记录有效字符串的下标
}
break;
}
}
}
return min == sLen + 1 ? "" : s.substring(index, index + min);
}
2.滑动窗口
在暴力解法中,第一次循环与第二次循环会有重复判断的部分,因此可以使用滑动窗口;
用tArr存放t中所有字符的信息,用count表示有效字符的个数;
定义两个指针left和right,均指向s的第一个字符,将right指向的字符in存放到sArr中,锁sArr[in] <= tArr[in],就说明in是一个有效字符,将count++;
当count与tLen相等时,就更新符合条件的子数组的长度以及下标,再将left指向的字符out移除sArr,在移除前,要判断out是否为有效字符,若是,则将count--,再将left向右移动一位,反之直接将left向右移动一位,之后再次进入循环进行判断,找到最短的子串以及该字串的下标,带啊吗如下:
public String minWindow(String s, String t) {
int sLen = s.length();
int tLen = t.length();
int[] tArr = new int[128];
for (int i = 0; i < tLen; i++) {
char ch = t.charAt(i);
tArr[ch]++;
}
int[] sArr = new int[128];
int min = sLen + 1;//子串长度最小值
int index = 0;//最短子串下标
for (int left = 0, right = 0, count = 0; right < sLen; right++) {
char in = s.charAt(right);
sArr[in]++;
if (sArr[in] <= tArr[in]) {
count++;//是有效字符
}
while (count == tLen) {
if (min > right - left + 1) {
min = right - left + 1;
index = left;
}
char out = s.charAt(left);
if (sArr[out] <= tArr[out]) {//是有效字符
count--;
}
sArr[out]--;
left++;
}
}
return min == sLen + 1 ? "" : s.substring(index, index + min);
}
注意,定义min的方式为int min = sLen + 1;是为了保证当sLen < tLen时,直接将s作为最短子串返回。
希望大家积极讨论!!