leetcode 76 最小覆盖子串
参考资料:
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 最小覆盖子串相关推荐
- Leetcode 76最小覆盖子串77组合78子集
新人公众号(求支持):bigsai 专注于Java.数据结构与算法,一起进大厂不迷路! 算法文章题解全部收录在github仓库bigsai-algorithm,求star! 关注回复进群即可加入力扣打 ...
- LeetCode 76. 最小覆盖子串 (滑动窗口哈希表)
LeetCode 76. 最小覆盖子串 思路: 准备一个map1记录字符串t(字符, 字符个数) 准备一个map2记录在s的窗口中所包含的t串字符(字符,字符个数) 左端点收缩条件:窗口内已经覆盖了t ...
- LeetCode - 76 最小覆盖子串
目录 题目来源 题目描述 示例 提示 题目解析 算法源码 题目来源 76. 最小覆盖子串 - 力扣(LeetCode) 题目描述 给你一个字符串 s .一个字符串 t .返回 s 中涵盖 t 所有字符 ...
- LeetCode 76. 最小覆盖子串(滑动窗口)
1. 题目 给你一个字符串 S.一个字符串 T,请在字符串 S 里面找出:包含 T 所有字母的最小子串. 示例: 输入: S = "ADOBECODEBANC", T = &quo ...
- java最小子串覆盖_LeetCode 76. 最小覆盖子串
LeetCode 76. 最小覆盖子串 题目 给你一个字符串 S.一个字符串 T,请在字符串 S 里面找出:包含 T 所有字母的最小子串. 示例: 输入: S = "ADOBECODEBAN ...
- 【LeetCode】【HOT】76. 最小覆盖子串(滑动窗口)
[LeetCode][HOT]76. 最小覆盖子串 文章目录 [LeetCode][HOT]76. 最小覆盖子串 package hot;public class Solution76 {public ...
- LeetCode高频题76. 最小覆盖子串:欠账还债还款问题,子串考虑i开头的情况所有答案更新一波
LeetCode高频题76. 最小覆盖子串:欠账还债还款问题,子串考虑i开头的情况所有答案更新一波 提示:本题是系列LeetCode的150道高频题,你未来遇到的互联网大厂的笔试和面试考题,基本都是从 ...
- 【LeetCode】76. 最小覆盖子串 (Java代码)
[LeetCode]76. 最小覆盖子串 (Java代码) 来源:力扣(LeetCode) 题目链接:https://leetcode.cn/problems/minimum-window-subst ...
- 72.编辑距离105.前序中序遍历序列构造二叉树151.翻转字符串里的单词104.二叉树的最大深度76.最小覆盖子串110.平衡二叉树31.下一个排列
72.编辑距离 给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 .你可以对一个单词进行如下三种操作:插入一个字符,删除一个字符,替换一个字符. ...
最新文章
- 图解TCP/UDP原理!秒懂!
- 组件三层_Angular 练级之旅(8)-Zorro Select组件的实现和进阶
- word自带公式编辑_怎样在word2013中快速插入数学公式
- 联想拯救者Y7000系列笔记本电脑外接显示器解决方案
- mysql tcp 远程_MySQL开启远程访问
- standalone vue initialization process
- Linux 性能监控 : CPU 、Memory 、 IO 、Network
- Qt移动应用开发(八):实现跨平台的QML和OpenGL混合渲染
- tail将输出的日志放到文件中_如何将Spring Boot应用中日志输出格式改为JSON?
- 常用前端Js框架简介
- 单片机c语言曲普两只蝴蝶,51单片机蜂鸣器播放音乐代码(生日快乐 两只蝴蝶 祝你平安)...
- 连载IT小说《失业的程序员》讲述一个Android开发者的奋斗史
- 机房收费系统---数据库设计说明书
- 无U盘的Ubuntu双系统安装方法
- android图片和文字设计,如何为图片加上精美文字?
- nginx: [emerg] still could not bind()
- python列表获取最后一个元素的方法_在Python中获取列表的最后一个元素
- python画图旋转图形_python – 如何将matplotlib图旋转90度?
- 威联通 php配置,威联通(qnap) NAS docker 安装 IYUU 步骤
- 显示设备的接口分类:VGA,HDMI,DVI等等
热门文章
- javaweb JAVA JSP记账管理系统财务管理系统(个人理财系统个人财务管理系统
- zabbix 6.2版本如何实现局域网内的硬件设备状态监控详解-部署安装-界面优化-web调试
- vivo领跑中国智能手机市场
- 【Proteus仿真】51单片机8路舵机点动±90°点动控制
- 计算机一级b证书图片p,只需两步,分分钟搞定证件照(内附福利)
- Monkey详解(事件型指令篇)-转
- 内存详解mdash;mdash;理解 JVM 如何使用 AIX 上的本机内存
- size (A,dim) 指定维数 大小
- 老猿学5G随笔:5G的三大业务场景eMBB、URLLC、mMTC
- 【Pr】实现视频最后的字幕从下往上的滑动