参考资料:
https://leetcode-cn.com/problems/minimum-window-substring/solution/zui-xiao-fu-gai-zi-chuan-by-leetcode-2/

解法一:滑动窗口

直觉

本问题要求我们返回字符串SS 中包含字符串TT的全部字符的最小窗口。我们称包含TT的全部字母的窗口为可行窗口。

可以用简单的滑动窗口法来解决本问题。

在滑动窗口类型的问题中都会有两个指针。一个用于延伸现有窗口的 rightright指针,和一个用于收缩窗口的leftleft 指针。在任意时刻,只有一个指针运动,而另一个保持静止。

本题的解法很符合直觉。我们通过移动right指针不断扩张窗口。当窗口包含全部所需的字符后,如果能收缩,我们就收缩窗口直到得到最小窗口。

答案是最小的可行窗口。

举个例子,S = “ABAACBAB”,T = “ABC”。则问题答案是 “ACB” ,下图是可行窗口中的一个。

算法

初始,leftleft指针和rightright指针都指向SS的第一个元素.

将 rightright 指针右移,扩张窗口,直到得到一个可行窗口,亦即包含TT的全部字母的窗口。

得到可行的窗口后,将lefttleftt指针逐个右移,若得到的窗口依然可行,则更新最小窗口大小。

若窗口不再可行,则跳转至 22。

重复以上步骤,直到遍历完全部窗口。返回最小的窗口。

class Solution {public String minWindow(String s, String t) {if (s.length() == 0 || t.length() == 0) {return "";}// Dictionary which keeps a count of all the unique characters in t.Map<Character, Integer> dictT = new HashMap<Character, Integer>();for (int i = 0; i < t.length(); i++) {int count = dictT.getOrDefault(t.charAt(i), 0);dictT.put(t.charAt(i), count + 1);}// Number of unique characters in t, which need to be present in the desired window.int required = dictT.size();// Left and Right pointerint l = 0, r = 0;// formed is used to keep track of how many unique characters in t// are present in the current window in its desired frequency.// e.g. if t is "AABC" then the window must have two A's, one B and one C.// Thus formed would be = 3 when all these conditions are met.int formed = 0;// Dictionary which keeps a count of all the unique characters in the current window.Map<Character, Integer> windowCounts = new HashMap<Character, Integer>();// ans list of the form (window length, left, right)int[] ans = {-1, 0, 0};while (r < s.length()) {// Add one character from the right to the windowchar c = s.charAt(r);int count = windowCounts.getOrDefault(c, 0);windowCounts.put(c, count + 1);// If the frequency of the current character added equals to the// desired count in t then increment the formed count by 1.if (dictT.containsKey(c) && windowCounts.get(c).intValue() == dictT.get(c).intValue()) {formed++;}// Try and co***act the window till the point where it ceases to be 'desirable'.while (l <= r && formed == required) {c = s.charAt(l);// Save the smallest window until now.if (ans[0] == -1 || r - l + 1 < ans[0]) {ans[0] = r - l + 1;ans[1] = l;ans[2] = r;}// The character at the position pointed by the// `Left` pointer is no longer a part of the window.windowCounts.put(c, windowCounts.get(c) - 1);if (dictT.containsKey(c) && windowCounts.get(c).intValue() < dictT.get(c).intValue()) {formed--;}// Move the left pointer ahead, this would help to look for a new window.l++;}// Keep expanding the window once we are done co***acting.r++;   }return ans[0] == -1 ? "" : s.substring(ans[1], ans[2] + 1);}
}

复杂度分析

时间复杂度: O(|S| + |T|)O(∣S∣+∣T∣),其中 |S|∣S∣ 和 |T|∣T∣ 代表字符串 SS 和 TT的长度。在最坏的情况下,可能会对SS 中的每个元素遍历两遍,左指针和右指针各一遍。

空间复杂度: O(|S| + |T|)O(∣S∣+∣T∣)。当窗口大小等于|S|∣S∣时为 SS。当 |T|∣T∣ 包括全部唯一字符时为 TT 。

解法二:优化滑动窗口

直觉

对上一方法进行改进,可以将时间复杂度下降到 O(2*|filtered_S| + |S| + |T|)O(2∗∣filtered_S∣+∣S∣+∣T∣),其中 filtered_Sfiltered_S 是从SS中去除所有在TT中不存在的元素后,得到的字符串。

当 |filtered_S| <<< |S|∣filtered_S∣<<<∣S∣时,优化效果显著。这种情况可能是由于TT 的长度远远小于SS,因此SS 中包括大量TT中不存在的自负。

算法

我们建立一个 filtered_Sfiltered_S列表,其中包括 SS 中的全部字符以及它们在SS的下标,但这些字符必须在 TT中出现。

S = “ABCDDDDDDEEAFFBC” T = “ABC”
filtered_S = [(0, ‘A’), (1, ‘B’), (2, ‘C’), (11, ‘A’), (14, ‘B’), (15, ‘C’)]

此处的(0, ‘A’)表示字符’A’ 在字符串SS的下表为0。

现在我们可以在更短的字符串filtered_Sfiltered_S中使用滑动窗口法。

import javafx.util.Pair;class Solution {public String minWindow(String s, String t) {if (s.length() == 0 || t.length() == 0) {return "";}Map<Character, Integer> dictT = new HashMap<Character, Integer>();for (int i = 0; i < t.length(); i++) {int count = dictT.getOrDefault(t.charAt(i), 0);dictT.put(t.charAt(i), count + 1);}int required = dictT.size();// Filter all the characters from s into a new list along with their index.// The filtering criteria is that the character should be present in t.List<Pair<Integer, Character>> filteredS = new ArrayList<Pair<Integer, Character>>();for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);if (dictT.containsKey(c)) {filteredS.add(new Pair<Integer, Character>(i, c));}}int l = 0, r = 0, formed = 0;Map<Character, Integer> windowCounts = new HashMap<Character, Integer>();  int[] ans = {-1, 0, 0};// Look for the characters only in the filtered list instead of entire s.// This helps to reduce our search.// Hence, we follow the sliding window approach on as small list.while (r < filteredS.size()) {char c = filteredS.get(r).getValue();int count = windowCounts.getOrDefault(c, 0);windowCounts.put(c, count + 1);if (dictT.containsKey(c) && windowCounts.get(c).intValue() == dictT.get(c).intValue()) {formed++;}// Try and co***act the window till the point where it ceases to be 'desirable'.while (l <= r && formed == required) {c = filteredS.get(l).getValue();// Save the smallest window until now.int end = filteredS.get(r).getKey();int start = filteredS.get(l).getKey();if (ans[0] == -1 || end - start + 1 < ans[0]) {ans[0] = end - start + 1;ans[1] = start;ans[2] = end;}windowCounts.put(c, windowCounts.get(c) - 1);if (dictT.containsKey(c) && windowCounts.get(c).intValue() < dictT.get(c).intValue()) {formed--;}l++;}r++;   }return ans[0] == -1 ? "" : s.substring(ans[1], ans[2] + 1);}
}

复杂度分析

时间复杂度 : O(|S| + |T|)O(∣S∣+∣T∣), 其中 |S|∣S∣ 和 |T|∣T∣ 分别代表字符串SS 和 TT的长度。 本方法时间复杂度与方法一相同,但当|filtered_S|∣filtered_S∣<<<|S|∣S∣时,复杂度会下降,因为此时迭代次数是 2*|filtered_S| + |S| + |T|2∗∣filtered_S∣+∣S∣+∣T∣。
空间复杂度 : O(|S| + |T|)O(∣S∣+∣T∣)。

总结

两次代码大部分相同,就是多了一个List。然后左右指针left,right变成指向List里面的元素。查找范围有字符串S到了List。

leetcode 76 最小覆盖子串相关推荐

  1. Leetcode 76最小覆盖子串77组合78子集

    新人公众号(求支持):bigsai 专注于Java.数据结构与算法,一起进大厂不迷路! 算法文章题解全部收录在github仓库bigsai-algorithm,求star! 关注回复进群即可加入力扣打 ...

  2. LeetCode 76. 最小覆盖子串 (滑动窗口哈希表)

    LeetCode 76. 最小覆盖子串 思路: 准备一个map1记录字符串t(字符, 字符个数) 准备一个map2记录在s的窗口中所包含的t串字符(字符,字符个数) 左端点收缩条件:窗口内已经覆盖了t ...

  3. LeetCode - 76 最小覆盖子串

    目录 题目来源 题目描述 示例 提示 题目解析 算法源码 题目来源 76. 最小覆盖子串 - 力扣(LeetCode) 题目描述 给你一个字符串 s .一个字符串 t .返回 s 中涵盖 t 所有字符 ...

  4. LeetCode 76. 最小覆盖子串(滑动窗口)

    1. 题目 给你一个字符串 S.一个字符串 T,请在字符串 S 里面找出:包含 T 所有字母的最小子串. 示例: 输入: S = "ADOBECODEBANC", T = &quo ...

  5. java最小子串覆盖_LeetCode 76. 最小覆盖子串

    LeetCode 76. 最小覆盖子串 题目 给你一个字符串 S.一个字符串 T,请在字符串 S 里面找出:包含 T 所有字母的最小子串. 示例: 输入: S = "ADOBECODEBAN ...

  6. 【LeetCode】【HOT】76. 最小覆盖子串(滑动窗口)

    [LeetCode][HOT]76. 最小覆盖子串 文章目录 [LeetCode][HOT]76. 最小覆盖子串 package hot;public class Solution76 {public ...

  7. LeetCode高频题76. 最小覆盖子串:欠账还债还款问题,子串考虑i开头的情况所有答案更新一波

    LeetCode高频题76. 最小覆盖子串:欠账还债还款问题,子串考虑i开头的情况所有答案更新一波 提示:本题是系列LeetCode的150道高频题,你未来遇到的互联网大厂的笔试和面试考题,基本都是从 ...

  8. 【LeetCode】76. 最小覆盖子串 (Java代码)

    [LeetCode]76. 最小覆盖子串 (Java代码) 来源:力扣(LeetCode) 题目链接:https://leetcode.cn/problems/minimum-window-subst ...

  9. 72.编辑距离105.前序中序遍历序列构造二叉树151.翻转字符串里的单词104.二叉树的最大深度76.最小覆盖子串110.平衡二叉树31.下一个排列

    72.编辑距离 给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 .你可以对一个单词进行如下三种操作:插入一个字符,删除一个字符,替换一个字符. ...

最新文章

  1. 图解TCP/UDP原理!秒懂!
  2. 组件三层_Angular 练级之旅(8)-Zorro Select组件的实现和进阶
  3. word自带公式编辑_怎样在word2013中快速插入数学公式
  4. 联想拯救者Y7000系列笔记本电脑外接显示器解决方案
  5. mysql tcp 远程_MySQL开启远程访问
  6. standalone vue initialization process
  7. Linux 性能监控 : CPU 、Memory 、 IO 、Network
  8. Qt移动应用开发(八):实现跨平台的QML和OpenGL混合渲染
  9. tail将输出的日志放到文件中_如何将Spring Boot应用中日志输出格式改为JSON?
  10. 常用前端Js框架简介
  11. 单片机c语言曲普两只蝴蝶,51单片机蜂鸣器播放音乐代码(生日快乐 两只蝴蝶 祝你平安)...
  12. 连载IT小说《失业的程序员》讲述一个Android开发者的奋斗史
  13. 机房收费系统---数据库设计说明书
  14. 无U盘的Ubuntu双系统安装方法
  15. android图片和文字设计,如何为图片加上精美文字?
  16. nginx: [emerg] still could not bind()
  17. python列表获取最后一个元素的方法_在Python中获取列表的最后一个元素
  18. python画图旋转图形_python – 如何将matplotlib图旋转90度?
  19. 威联通 php配置,威联通(qnap) NAS docker 安装 IYUU 步骤
  20. 显示设备的接口分类:VGA,HDMI,DVI等等

热门文章

  1. javaweb JAVA JSP记账管理系统财务管理系统(个人理财系统个人财务管理系统
  2. zabbix 6.2版本如何实现局域网内的硬件设备状态监控详解-部署安装-界面优化-web调试
  3. vivo领跑中国智能手机市场
  4. 【Proteus仿真】51单片机8路舵机点动±90°点动控制
  5. 计算机一级b证书图片p,只需两步,分分钟搞定证件照(内附福利)
  6. Monkey详解(事件型指令篇)-转
  7. 内存详解mdash;mdash;理解 JVM 如何使用 AIX 上的本机内存
  8. size (A,dim) 指定维数 大小
  9. 老猿学5G随笔:5G的三大业务场景eMBB、URLLC、mMTC
  10. 【Pr】实现视频最后的字幕从下往上的滑动