当前位置:网站首页>LeetCode高频题76. 最小覆盖子串:欠账还债还款问题,子串考虑i开头的情况所有答案更新一波
LeetCode高频题76. 最小覆盖子串:欠账还债还款问题,子串考虑i开头的情况所有答案更新一波
2022-08-05 22:32:00 【冰露可乐】
LeetCode高频题76. 最小覆盖子串:欠账还债还款问题,子串考虑i开头的情况所有答案更新一波
提示:本题是系列LeetCode的150道高频题,你未来遇到的互联网大厂的笔试和面试考题,基本都是从这上面改编而来的题目互联网大厂们在公司养了一大批ACM竞赛的大佬们,吃完饭就是设计考题,然后去考应聘人员,你要做的就是学基础树结构与算法,然后打通任督二脉,以应对波云诡谲的大厂笔试面试题!你要是不扎实学习数据结构与算法,好好动手手撕代码,锻炼解题能力,你可能会在笔试面试过程中,连题目都看不懂!比如华为,字节啥的,足够让你读不懂题
题目
给你一个字符串 s 、一个字符串 t 。
返回 s 中涵盖 t 所有字符的最小子串。
如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
注意:
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/minimum-window-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
一、审题
示例 1:
输入:s = “ADOBECODEBANC”, t = “ABC”
输出:“BANC”
示例 2:
输入:s = “a”, t = “a”
输出:“a”
示例 3:
输入: s = “a”, t = “aa”
输出: “”
解释: t 中两个字符 ‘a’ 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。
提示:
1 <= s.length, t.length <= 105
s 和 t 由英文字母组成
二这题可不是动态规划,我试过,搞不出来,这题是欠账还款策略
子串嘛,不就是考虑以i开头,或者结尾的情况
这不在乎顺序,咱就是要s包了t中的字符
长的s也行
短的子串也行
咱得找最短的那个子串,恰好包含t所有字符即可
不是啥动态规划,这个题就是欠债还款策略
o(n)拿下
(0)当s长度不够t,那包含失败了
(1)只有s长度N大于t长度M才行
建立欠账表【哈希表,数组也行】
map
记录所有字符,欠几个??统计词频,拢共欠all个
整一个L–R把s中的子串包含进来,有的字符,还给map
只要map>=0,就是有效的还款
map<0可不行,这样就是多给你了字符
比如,下图
L–R范围内,多给了s有2个,无效还款
多给了一个b,无效还款
比如下图,本来还了一个c,又多出来一个c,还款无效,map中c那词频为负
当下面a换回来之后,你发现a还完了,all=0
all一旦是0,这时候就算是s已经整体把t包含了,因为你all全部还完了
目前啥含义??
即:子串目前以L=0开头,最短的长度就是R-L+1,这样才能让all=0,还完了所有t的字符
不过呢,因为map还有负,所以就是说s中L–R包含的字符过多了
否则map咋变负了呢
必须以0开头的子串,让all=0,的长度min=R-L+1
好,我让L++,我们去找L=1开头的情况,它能否得到更短的答案
此时你发现s刚刚多还了一个,现在map中s变-1,说明我们把多还的s拿走
注意,此时all=0还是不变的,说明我们当前L–R范围内还是能还完t的所有字符
结算一个答案,更新给min=R-L+1
继续,我让L++,我们去找L=2开头的情况,它能否得到更短的答案
这时候你发现L–R吐出去a,但是这样的话,map又要欠款了,欠了a
all=1,说明又欠了
这时候不能结算结果,更新min,而是让R继续扩,看看能不能找到a换回来
总之,L从左到右,每一个位置i做一次开头,咱们让R使劲扩,直到我们还完all=0,就要更新一次答案
整体每次就是还款的事情,all=0结算,然后认为L++,让map恢复,all恢复,不断更新min
美滋滋
代码细节
map用数组,0–255空间,每个位置一个ASCII码
字符a–z就在里面的
要么R++,要么L++,咱们L,R永远不回头,所以就是o(n)一遍过
我们要的结果是子串
当结果最短时,我要把L位置记录一波,R记录一波
这样我们剪切L–R范围内的子串返回结果
设置窗口往往都是[L–R)左闭右开,右开那个R不算
L=0,R=0,最开始就没有拉进来,R即将要被扩进来
只要L处map还太多,可以提前先吐出去,保证L–R尽量短,同时也是包住t所有字符就行
最开始min长度设置为-1,表示还么有结算过,第一次结算就给它了
后续有更短的长度R-L+1,才有必要更新给min
当然,min直接用min函数更新即可
当all=0时,结算min之后,手动让L吐出去,此时人为让map把L这里欠款,all也欠
看代码:
//复习:还款策略
public String minWindowReview(String s, String t) {
if(s.length() < t.length()) return "";
//转字符数组,我们好操作
char[] str = s.toCharArray();
char[] ttr = t.toCharArray();
//欠了t所哟字符
int all = t.length();
//统计词频
int[] map = new int[256];
for (int i = 0; i < ttr.length; i++) {
map[ttr[i]]++;//t就是咱们要还的
}
int min = Integer.MAX_VALUE;//目前长度很长,无效
int L = 0;
int R = 0;//还款区间
int ansL = 0;
int ansR = 0;//中途发现有更短的长度就记录当前L--R,方便咱们回复结果
while (R != str.length){
//一旦R到达str末尾,说明所有情况都考虑了
//R扩进来,换款,看看有效还款吗?
map[str[R]]--;//还给t
if (map[str[R]] >= 0) all--;//有效的还款,当map变负了就不行,还多了
if (all == 0){
//刚刚好还完的话要结算了
//还之前咱们尽量让L缩短一点,否则结算太长没必要的,map为负就是L那边还太多,要拿走
while (map[str[L]] < 0) map[str[L++]]++;
//一旦缩到L--R已经是最短的了,看看此时长度是否更短了,或者第一次结算
if (R - L + 1 < min){
min = Math.min(min, R - L + 1);//更新最短长度
ansL = L;//记录这个就是当前找到的最短区间
ansR = R;
}
//结算之后,立马人为吐出L那个字符,人为欠债,探索别的L开头的可能性
map[str[L++]]++;//人为吐L,L++
all++;//L吐则必然欠债
}
//没还完还需R++继续换
R++;
}
return min == Integer.MAX_VALUE ? "" : s.substring(ansL, ansR + 1);//左闭右开
}
最开始一来R=0,就是咱们要还款的字符位置,如果有效就让all–
如果all没有变0,还需要继续扩R
如果all=0了,说经已经L–R包含了所有t字符
此时,可能L那个位置是多还的字符,map为负,我们需要提前吐出来
保证L–R最短
直到map那是0,就代表恰好还完,而且L–R不能再缩小了
这样的话,就可以结算了
结算min有更小就要记录更小的位置ansL 和 ansR
之后,立马人为让L++,又增加all,欠债欠起来,探索新的L开头的答案会不会更短
持续玩下去,这样的话,就把所有可能的结果搞定了
测试:
public static void test(){
String s = "ADOBECODEBANC";
String t = "ABC";
Solution solution = new Solution();
System.out.println(solution.minWindow(s, t));
System.out.println(solution.minWindowReview(s, t));
}
public static void main(String[] args) {
test();
}
结果非常OK
BANC
BANC
LeetCode测试


速度够快吧,o(n)一遍搞定了就
关键在理解,map记录t中需要换的各个字符
all记录t长度,就是总体要还这么多
然L–R内扩R,一个个把all还了
map变负即使还多了,需要吐出来
然后整L–R既是最短的,又是各个好还完t所有字符,这样就可以结算一个结果给min
顺便记录L–R,用于返回结果
当所有L开头的情况,答案都考虑了,o(n)速度的结果也就出来了
总结
提示:重要经验:
1)本题不是动态规划,自然子串就是考虑所有位置i开头的答案,先建立欠债表,然后还债,刚刚还完就让L–R缩最短,然后认为欠债,考虑别的L开头的可能更短的答案;
3)笔试求AC,可以不考虑空间复杂度,但是面试既要考虑时间复杂度最优,也要考虑空间复杂度最优。
边栏推荐
猜你喜欢

Smart Warehouse Manager - WMS

智慧的仓库管家——WMS

集群监控——集成Grafana

DIKW体系对AI的影响

60:第五章:开发admin管理服务:13:开发【新增/修改友情链接,接口】的新增功能;(向MongoDB中,新增数据)(操作MongoDB的Dao层接口,得继承MongoRepository接口;)

Pagoda measurement - e-commerce ERP invoicing system source code
![[GKCTF 2021]easycms](/img/8d/1d83f81f2130a44e98f2cf3dfcf71c.png)
[GKCTF 2021]easycms

Centos7 source code compile and install postgresql 11.7

Qt uses wget to download file case

Is the code more messy?That's because you don't use Chain of Responsibility!
随机推荐
Nanoprobes丨Nanogold 标记条带的凝胶染色
智慧的仓库管家——WMS
Day11:二叉树---->满~、完全~、堆
论如何下载网页中的m3u8/ts视频
大家常说的表空间到底是什么?究竟什么又是数据表呢?
Quick Sort
CAN-Oe channel configuration method
Is it better to design vias as small as possible?
将trivydb转转化为mysql、sqlite的小工具
C language basic walkthrough(9)
Ext.js项目(一)
60: Chapter 5: Develop admin management services: 13: Develop new functions of [Add/Modify Friendship Links, Interfaces]; (Add data to MongoDB) (To operate the Dao layer interface of MongoDB, you must
归并排序(Merge Sort)
Redis 定长队列的探索和实践
LeetCode 每日一题——623. 在二叉树中增加一行
[ssh] Solve the problem that the debian 11 system crt cannot ssh login
[Flask] Deploy flask using gevent
NVM quick installation tutorial, only one
有关CRT密码反编译问题
关于 Invalid prop: type check failed for prop “index“. Expected String, got Undefined