76.最小覆盖子串
思路
错误思路记录(自己记录,不要看):以t的长度作为初始区间长度,每个长度从头开始切子串,一直到末尾,因为从最小长度开始,如果找到满足条件的子串,即退出循环并return,找不到就区间长度加1,然后从头开始。对于“满足条件——统计子串中t中每个字符的个数”,写了统计String中某个字符出现个数的函数,对于子串中每个字符,如果其数目小于子串的数目,结束循环,区间步进。这种方法暴力搜索,时间复杂度太高,对于很长的字符串会报错——超出时间限制
- 滑动窗口的本质是:在滑动窗口类型的问题中都会有两个指针,一个用于「延伸」现有窗口的 rr 指针,和一个用于「收缩」窗口的 ll 指针。一个静止一个滑动。
- 题解思路:初始左右指针都在0下标处,首先右指针r向前步进,直到l和r之间的子串包含了t的所有字符,然后l向前步进,寻找目前r下的最优子串,当去掉l当前字符会导致不满足包含条件时,这个子串即当前r下的最优子串,将其记录。然后l不动,r继续步进,重复上诉操作,此时r下的最优子串长度若比之前的小,更新最优子串。—— 记录字符出现数使用128长度的int数组,下标指的字符的ASCII码(一共128个字符,其ASCII码为0-127)
代码
- 代码
class Solution {
public String minWindow(String s, String t) {
if (s.length()==0||t.length()==0) return "";
int l=0 , r=0 , total=t.length() ,start=0 ,size=Integer.MAX_VALUE;
int[] need = new int[128];
for (int i = 0; i < t.length(); i++) {
need[t.charAt(i)]++;
}
while(r<s.length()){
if(need[s.charAt(r)]>0)
total--;
need[s.charAt(r)]--;
if (total==0){
while (need[s.charAt(l)]<0){
need[s.charAt(l)]++;
l++;
}
if (r-l+1<size){
size=r-l+1;
start=l;
}
need[s.charAt(l)]++;
l++;
total++;
}
r++;
}
if (size!=Integer.MAX_VALUE) return s.substring(start,start+size);
else return "";
}
}
- 代码思路:
①初始即可判断返回值的条件要首先列出:本题当s或者t长度为0时返回""
②然后声明变量:本题变量包括左指针l、右指针r、int数组need[]存储t中每个字符还需要几个(ASCII码为0-127)、一个total存储子区间一共还差几个字符、start存储目前最优区间开始下标、size存储目前最优区间的长度(初始长度设为最大int值)
③右指针一直在向前步进,每次新的r【1】先判断是不是需要的,需要的话total更新,然后条件判断外部更新need数组(因为不管是不是需要,都要一样的操作:更新need;而需要的话有不同的操作:更新total)【2】然后因为新的r更新了total,此时判断,当total为0时证明右指针满足区间包含所有字符,这时要【短暂停留,步进左指针】,当当前字符的need中值为负,就更新need值然后步进,循环停止时当前字符need值为0,不可以再+1,这时找到了当前r下的最优l,需要更新最优区间(当前区间比存储的size小的话,证明更优,更新start和size),因为需要继续步进进行,当前条件下,更新l的need,更新total(因为减少了一个必需字符),然后l步进一个【3】不管是有没有短暂停留,r正常步进,直到到边界
④如果size还为初始值就返回"",否则返回当前start到start+size的子串(substring为左闭右开)
技巧和总结
- 滑动区间的意思不是一个区间整体左右滑,而是左右指针滑动,区间大小改变,以寻找满足条件的。
- 思路一定要梳理好,每一种情况都考虑,而对于复杂的循环,放在大局思考。如本题,如果每次寻找到r,然后更新l,然后再更新r,就不知道怎么循环,但是整体来看,r一直在从0到末尾的路上,只不过有一个r恰好满足让l步进的条件,在其循环体里直接l处理完,r继续步进(只是短暂停留)。
- 需要一个很大的初始值:
int size=Integer.MAX_VALUE;
- 初始可以判断排除的条件,开始之前直接处理了,如本题字符串为空的条件。
- subString为左闭右开。
- 需要记录字符出现个数这种,均可以参考本题处理方法,采用128长度的int数组,每一个下标代表一个字符,而a[‘s’]代表’s’的ASCII码为下标元素。