题目及测试
package pid076;
/*最小覆盖子串
给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字母的最小子串。
示例:
输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"
说明:
如果 S 中不存这样的子串,则返回空字符串 ""。
如果 S 中存在这样的子串,我们保证它是唯一的答案。
*/
public class main {
public static void main(String[] args) {
String [] testTable = {"ADOBECODEBANC","BANC"};
String [] testTable2 = {"ABC","BC"};
for (int i=0;i<3;i++) {
test(testTable[i],testTable2[i]);
}
}
private static void test(String ito,String ito2) {
Solution solution = new Solution();
String rtn;
long begin = System.currentTimeMillis();
System.out.println(ito);
System.out.println(ito2);
//开始时打印数组
rtn= solution.minWindow(ito,ito2);//执行程序
long end = System.currentTimeMillis();
System.out.println("rtn" );
System.out.print(rtn);
System.out.println();
System.out.println("耗时:" + (end - begin) + "ms");
System.out.println("-------------------");
}
}
解法1(别人的)
明显是要使用滑动窗口,比较复杂的一点是,滑动窗口的长度是可变的。
所以区别于固定滑动窗口的达到窗口长度后随着右指针向右移动一位左指针也要移动一位
滑动窗口更改长度的原因是在滑动窗口中去掉不需要的字符
使用数组hash存储需要的字符串,根据字符串t,里面hash[ tt[i] -'0']++,需要的字符为正数,不需要的为0或者负数。
使用count记录匹配的字符数,一开始为t.length,如果为0,代表完全匹配,刷新minLength和results
right每次向右移动一位,hash[ ss[right] -'0']- - ,表示需要的字符数减少,如果hash[ ss[right] -'0']>=0 代表right是需要的字符。
然后不断让left向右移hash[ ss[left] -'0']<0 ,代表left是不需要的字符,自然可以向右移。
最后判断count是否为0
class Solution {
public String minWindow(String s, String t) {
char[] ss = s.toCharArray();
char[] tt = t.toCharArray();
//用来存储滑动窗口中的值(注意还有小写的)
int[]hash = new int[256];
//最小子串的长度
int minlength = s.length();
//最小子串
String results = "";
for(char smallt:tt)
{
hash[smallt-'0']++;
}
int left = 0;
int right = 0;
int count = tt.length;
for(;right<ss.length;right++)
{
hash[ss[right]-'0']--;
//说明当前的字符存在于T中,且当前滑动窗口中还需要该字符
//后面这个且的意思就是比如我的T为ABC,我只有第一次遇到A才会count--,而第二次就不会了,
if(hash[ss[right]-'0']>=0)
{
count--;
}
//right又遇到了left处的字符(特指遇到T中存在的),或left处的字符不是T中需要的,就右移左指针直到找到需要的或者left=right
while(left<right&&hash[ss[left]-'0']<0)
{
hash[ss[left]-'0']++;
left++;
}
//这里大于等于是防止最小覆盖子串就是s其本身
if(count==0&&minlength>=right-left+1)
{
minlength = right-left+1;
results = s.substring(left,right+1);
}
}
return results;
}
}
解法2(成功,5ms,较快)
class Solution {
public String minWindow(String s, String t) {
if(t.length() == 0 || s.length() == 0) {
return "";
}
int[] base = new int[58];
for(int i=0;i<t.length();i++) {
base[t.charAt(i) - 'A']++;
}
int[] contain = new int[58];
int valid = 0;
int left = 0;
int right = 0;
int min = Integer.MAX_VALUE;
String result = "";
while(left <s.length()) {
if(valid < t.length() && right <s.length()) {
int nowIndex = s.charAt(right) - 'A';
contain[nowIndex]++;
right++;
if(contain[nowIndex] <= base[nowIndex]) {
valid++;
}
}else {
int nowIndex = s.charAt(left) - 'A';
contain[nowIndex]--;
left++;
if(contain[nowIndex] < base[nowIndex]) {
valid--;
}
}
if(valid == t.length()) {
if(right - left < min) {
min = right - left;
result = s.substring(left, right);
}
}
}
return result;
}
}