ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

542,滑动窗口解最小覆盖子串

2021-06-15 07:08:09  阅读:183  来源: 互联网

标签:子串 map right 窗口 字符 int 542 滑动 left


Spring is when you feel like whistling even with a shoe full of slush.

所谓春天,就是即使鞋子灌满泥巴,仍然想吹起口哨。

问题描述

给你一个字符串s、一个字符串t。返回s中涵盖t所有字符的最小子串。如果s中不存在涵盖t所有字符的子串,则返回空字符串""。

 

注意:如果s中存在这样的子串,我们保证它是唯一的答案。

 

示例 1:

输入:s = "ADOBECODEBANC", t = "ABC"

输出:"BANC"

示例 2:

输入:s = "a", t = "a"

输出:"a"

 

提示:

  • 1 <= s.length, t.length <= 10^5

  • s 和 t 由英文字母组成

 

滑动窗口解决

这题让求的是s中能覆盖t的最小子串,看到这题首先想到的就是滑动窗口。使用两个指针一个left,一个right,分别表示窗口的左边界和右边界。

 

  • 当窗口内的所有字符不能覆盖t的时候,要扩大窗口,也就是right往右移。

  • 当窗口内的所有字符可以覆盖t的时候,记录窗口的起始位置以及窗口的长度,然后缩小窗口(因为这里求的是能覆盖的最小子串),left往右移。如果缩小的窗口还能覆盖t,保存长度最小的窗口即可。

  • 重复上面的操作,直到窗口的右边不能再移动为止。

 

这里我以示例1为例做个视频,来看一下具体操作过程,加深一下理解。(如果看不清,可以切换横向全屏观看)

原理搞懂了,代码就简单多了,但是这里有个关键点,就是怎么记录窗口内的元素,其实很简单,使用一个map就可以,来看下代码。

 1public String minWindow(String s, String t) {
2    //把t中的字符全部放到map中
3    Map<Character, Integer> map = new HashMap<>();
4    for (char ch : t.toCharArray())
5        map.put(ch, map.getOrDefault(ch, 0) + 1);
6
7    int left = 0;//窗口的左边界
8    int right = 0;//窗口的右边界
9
10    //满足条件的窗口开始位置
11    int strStart = 0;
12    //满足条件的窗口的长度
13    int windowLength = Integer.MAX_VALUE;
14
15    while (right < s.length()) {
16        //记录右指针扫描过的字符
17        char rightChar = s.charAt(right);
18        //如果右指针扫描的字符存在于map中,就减1
19        if (map.containsKey(rightChar))
20            map.put(rightChar, map.getOrDefault(rightChar, 0) - 1);
21        //记录之后右指针要往右移
22        right++;
23
24        //检查窗口是否把t中字符全部覆盖了,如果覆盖了,要移动窗口的左边界
25        //找到最小的能全部覆盖的窗口
26        while (check(map)) {
27            //如果现在窗口比之前保存的还要小,就更新窗口的长度
28            //以及窗口的起始位置
29            if (right - left < windowLength) {
30                windowLength = right - left;
31                strStart = left;
32            }
33            //移除窗口最左边的元素,也就是缩小窗口
34            char leftChar = s.charAt(left);
35            if (map.containsKey(leftChar))
36                map.put(leftChar, map.getOrDefault(leftChar, 0) + 1);
37            //左指针往右移
38            left++;
39        }
40    }
41    //如果找到合适的窗口就截取,否则就返回空
42    if (windowLength != Integer.MAX_VALUE)
43        return s.substring(strStart, strStart + windowLength);
44    return "";
45}
46
47//检查窗口是否把字符串t中的所有字符都覆盖了,如果map中所有
48// value的值都不大于0,则表示全部覆盖
49private boolean check(Map<Character, Integer> map) {
50    for (int value : map.values()) {
51        //注意这里的value是可以为负数的,为负数的情况就是,相同的字符右
52        // 指针扫描的要比t中的多,比如t是"ABC",窗口中的字符是"ABBC"
53        if (value > 0)
54            return false;
55    }
56    return true;
57}

上面注释已经写的很详细了,基本上也都能看懂,实际上我们还可以把HashMap换成数组,原理其实都是一样的,来看下代码

 1public String minWindow(String s, String t) {
2    int[] map = new int[128];
3    //记录字符串t中每个字符的数量
4    for (char ch : t.toCharArray())
5        map[ch]++;
6    //字符串t的数量
7    int count = t.length();
8    int left = 0;//窗口的左边界
9    int right = 0;//窗口的右边界
10    //覆盖t的最小长度
11    int windowLength = Integer.MAX_VALUE;
12    //覆盖字符串t开始的位置
13    int strStart = 0;
14    while (right < s.length()) {
15        if (map[s.charAt(right++)]-- > 0)
16            count--;
17        //如果全部覆盖
18        while (count == 0) {
19            //如果有更小的窗口就记录更小的窗口
20            if (right - left < windowLength) {
21                windowLength = right - left;
22                strStart = left;
23            }
24            if (map[s.charAt(left++)]++ == 0)
25                count++;
26        }
27    }
28    //如果找到合适的窗口就截取,否则就返回空
29    if (windowLength != Integer.MAX_VALUE)
30        return s.substring(strStart, strStart + windowLength);
31    return "";
32}

 

总结

滑动窗口类型的题也是最常见的,一般会有两个指针,分别指向窗口的左边界和右边界,如果窗口不满足条件我们就移动右边界来扩大窗口,如果满足条件我们可以移动左边界来缩小窗口,确定这个更小的窗口是否还满足条件……

 

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

521,滑动窗口解最大连续1的个数 III

443,滑动窗口最大值

407,动态规划和滑动窗口解决最长重复子数组

397,双指针求接雨水问题

 

 

截止到目前我已经写了500多道算法题了,为了方便大家阅读,我把部分算法题整理成了pdf文档,目前有900多页,大家可以在公众号中回复关键字“pdf”即可获取下载链接。

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=你点的每个赞,我都认真当成了喜欢

标签:子串,map,right,窗口,字符,int,542,滑动,left
来源: https://blog.51cto.com/u_4774266/2902942

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有