力扣76题:最小覆盖 字串(滑动串窗口)

给你一个字符串 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元素计数器增加

⑧:因为我已经把这个元素去掉了,所以在数组里面要增加一次,便于⑥的下一次执行

⑨:窗口左移

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值