给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。
注意:
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。
输入:s = "ADOBECODEBANC", t = "ABC" 输出:"BANC"
输入: s = "a", t = "aa" 输出: ""解释: t 中两个字符 'a' 均应包含在 s 的子串中, 因此没有符合条件的子字符串,返回空字符串。
暴力出奇迹!!!
好吧,太暴力了好像有点不太好,我们按照套路来,先看题目:
它说给你俩字符串,求t在s的最小包含字串,
好绕啊~~~,我们简单理解,就是s的一段连续的子串,并且还要全部包含t,并且时最短的,这道题之所以是困难,就是要比较多
import java.util.Iterator;
public class _76 {
public static void main(String[] args) {
String s = "ADOBECODEBANC";
String t = "ABC";
System.out.println(f(s, t));
}
private static String f(String s, String t) {
/*
* 滑动窗口核心思想:
*1.定义左右区间点[l,r],
* 2.当[l,r]包含t的所有元素时
* 3.[l+1,r],判断[l,r]是否再次包含t的所有元素,
* 4.包含:更新最短长度, 5.不包含:[l,r+1],判断[l,r]是否包含t的所有元素,
* 6.包含:[l+1,r],判断[l,r]是否再次包含t的所有元素...... 7.不包含:[l,r+1],判断[l,r]是否包含t的所有元素.....
* 8.到r最后一个元素,结束
*/
int arr[] = new int[128];
for (char i : t.toCharArray()) {
arr[i]++;
}
int cont = t.length();// 方便我们判断区间,是否包含t的全部元素
int l = 0;// 做区间
int r = 0;// 右区间
int min = Integer.MAX_VALUE;// 最小包含区间的长度
int start = 0;// 满足包含区间,上一次区间开始的位置
while (r < s.length()) {// 到了最后一位
char c = s.charAt(r);
if (arr[c] > 0) {//如果这个元素大于0,就说明当前这个元素在t里面存在,就把区间存在个数的cont--
cont--;
}
arr[c]--;//
r++;//窗口向右边扩大
while (cont == 0) {//当区间存在个数cont==0,区间内包含t的全部元素,进行区间缩小
if (r - l < min) {//判断区间大小,本题求最小区间,每次区间满足后都进行判断
min = r - l;
start = l;//开始下标记录,用于返回字符串时截取
}
char h = s.charAt(l);//区间的左边元素
if (arr[h] == 0) {//等于0时,我们就要把区间计数器++,因为窗口缩小了,已经把t的其中一个元素排除了,
cont++;
}
l++;//缩小区间
arr[h]++;//
}
}
if (min != Integer.MAX_VALUE) {
System.out.println(min);
return s.substring(start, start + min);
}
return "";
}
}
1.首先,定义左右区间[l,r],定义一个int[]arr来存放字母,128个位置可以把全部位置存住,z时125。
2. 循环每一个元素
3.判断每一个元素在数组中的个数是否大于o,由于t是会有重复的
4.当前元素在数组等于0的时候,我们就进行缩短区间,
5.当我们进行缩短区间的时候,判断一下窗口缩短的时候,排除的元素是否为t的元素,若是,我们就把计数器cont++;
注意!
while(cont==0){①
if(r-l<min){②
min=r-l;③
kai=l;④
}
char c2=s.charAt(l);⑤
if(arr[c2]==0){⑥
cont++;⑦
}
arr[c2]++;⑧
l++;⑨
}
这段代码是我认为最不好理解的代码,我们一句,一句讲解一下:
①:判断[l,r]中t的全部元素是否存在,因为前面的( arr[r]>0,cont-- )已经把元素计算了
②:判断最小字串,一旦当前字串小于上一个字串,我们就更改记录字串的数据
③:更新最短长度,方便最后传出的时候进行截取
④:更新开始下标,方便最后传出的时候进行截取
⑤:缩短窗口时,被除去的字母
⑥:这一段很难:一旦被除去的字母在数组中是0,那么我们就要把元素存在计数器cont++,
前面的①已经把不是t的内容的字母割去了
⑦:t元素计数器增加
⑧:因为我已经把这个元素去掉了,所以在数组里面要增加一次,便于⑥的下一次执行
⑨:窗口左移