76. 最小覆盖子串
剩下的题都有亿点难度,我还有十道题就写完了,二维动态已经差不多要忘记了,所以我准备先看看思路大概是怎么样的,再写最后一个模块。
今天的这题是之前遗留下来的,我当时觉得很难就没有再写了
出错点:
-
for(int r=0;r<s.length();r++) {
if(cntT[cs[r]]>0 && cntS[cs[r]]==cntT[cs[r]]) {
valid++;
}
今天写了一下大概是用滑动窗口能感觉出来,但是我就是不知道该怎么快速的统计s和t的数,我看了题解,我感觉很新奇,很快速的思路,统计的话,直接用对应的ascll码用数组来统计,快速的判断s的子串是否覆盖t时就:先统计t有多少种字符,然后当每一次右指针滑动的时候,都进行判断,判断此时右指针指向的字符是否属于t需要的一种,并且s子串达标了,s的统计字符+1,
然后就直接可以通过valid和required是否相等,由此可以直接进行缩小范围了。
题目:


题解:
java
class Solution {
public String minWindow(String s, String t) {
if (s == null || t == null || s.length() < t.length()) {
return "";
}
//由于本题大写字母和小写字母都有,为了方便,代码实现时可以直接创建大小为 128 的数组,保证所有 ASCII 字符都可以统计。这样可以直接统计字符对应的ascll码对应的出现次数
int[] cntS = new int[128];
int[] cntT = new int[128];
//先统计字符串t出现次数
for(char c:t.toCharArray()) {
cntT[c]++;
}
//统计需要多少个requiredValid
int requiredValid = 0;
for(int i=0;i<128;i++) {
if(cntT[i]>0) {
requiredValid++;
}
}
//创建记录包含t的最短字符串的左右索引
int resLeft = -1; //用来最后判断是否能够得到包含t的字符串
int resRight = s.length();
//滑行窗口的左指针,右指针可以直接在遍历s字符串的时候进行遍历
int l = 0;
//将s变成char数组,方便统计
char[] cs = s.toCharArray();
//创建valid
int valid = 0;
//遍历s,不断移动滑动窗口的右边界
for(int r=0;r<s.length();r++) {
//右指针次数加1
cntS[cs[r]]++;
//看是否符合有效结果,这里必须是==,这样才能使多出来的值不影响达标状态
if(cntT[cs[r]]>0 && cntS[cs[r]]==cntT[cs[r]]) {
valid++;
}
//说明可以进行缩小范围
while(valid==requiredValid) {
if(r-l<resRight-resLeft) {
resLeft=l;
//因为substring是左闭右开的begin,end
resRight=r+1;
}
//将左指针往右移动,缩小范围
cntS[cs[l]]--;
//直接将不符合的跳出循环
if(cntT[cs[l]]>0&&cntS[cs[l]]<cntT[cs[l]]) {
valid--;
}
l++;
}
}
if(resLeft==-1) {
return "";
}
else {
return s.substring(resLeft, resRight);
}
}
}