当前位置:网站首页>Leetcode (76) -- Minimum Covering substring
Leetcode (76) -- Minimum Covering substring
2022-06-29 23:52:00 【SmileGuy17】
Leetcode(76)—— Minimum cover substring
subject
Give you a string s 、 A string t . return s Covered by t The smallest string of all characters . If s There is no coverage in t Substring of all characters , Returns an empty string ""
.
Be careful :
- about t Duplicate characters in , The number of characters in the substring we are looking for must not be less than t The number of characters in the .
- If s There is such a substring in , We guarantee that it is the only answer .
Example 1:
Input :s = “ADOBECODEBANC”, t = “ABC”
Output :“BANC”
Example 2:
Input :s = “a”, t = “a”
Output :“a”
Example 3:
Input : s = “a”, t = “aa”
Output : “”
explain : t Two characters in ‘a’ Shall be included in s In the string of ,
Therefore, there is no qualified substring , Returns an empty string .
Tips :
- 1 1 1 <= s.length, t.length <= 1 0 5 10^5 105
- s and t It's made up of English letters
Advanced : You can design one in O ( n ) O(n) O(n) The algorithm to solve this problem in time ?
Answer key
Method 1 sliding window :
Ideas
Sliding window can be used to solve the character matching problem of some columns , Typical problems include : In string s s s The shortest substring found in , So that it can cover the target string t t t. For the target string t t t, We can use the string s s s Slide up the window , When the window contains t t t After all characters in , We will consider whether we can shrink the window according to the meaning of the question .
In the process of sliding the window , We can violently count whether the characters contained in the window meet the requirements of the topic , But this does not take advantage of the basic properties of sliding windows . in fact , The window sliding process can be divided into the following two basic operations :
- Slide the right edge of the window one bit to the right : Add a new character at the right end of the window , But the other characters in the window have not changed ;
- Slide the left edge of the window one bit to the right : A character slides out at the left end of the window , But the other characters in the window have not changed .
therefore , We can consider in 「 One in, one out 」 Based on these two basic operations .
This question requires us to return the string s s s Contains the string t t t The smallest window for all characters of the . Include us t t t The window of all letters of is 「 feasible 」 window .
We can solve this problem with the idea of sliding window . In sliding window type problems, there will be two pointers , One for the 「 extend 」 Of existing windows r r r The pointer , And a for 「 shrinkage 」 Window l l l The pointer . At any moment , There's only one pointer moving , And the other is still . We are s s s Slide up the window , By moving r r r The pointer keeps expanding the window . When the window contains t t t After all the required characters , If you can shrink , We shrink the window until we get the smallest Window .
How to determine whether the current window contains all t t t What about the required characters ?
We can use a hash table to represent t t t All the characters in and their existing numbers ( be equal to 0 It means that the demand is just met , Greater than 0 To express a lack of , Less than 0 Indicates exceeding ), Use a hash table to dynamically maintain all the characters in the window and their number , If this dynamic table contains t t t All characters in the hash table , And the corresponding number is not less than t t t The number of characters in the hash table , So the current window is 「 feasible 」 Of .
Be careful : here t t t Duplicate characters may appear in , So we need to record the number of characters .
Consider how to optimize ?
If s = X X ⋯ X A B C X X X X s = {\rm XX \cdots XABCXXXX} s=XX⋯XABCXXXX, t = A B C t = {\rm ABC} t=ABC, So clearly [ X X ⋯ X A B C ] {\rm [XX \cdots XABC]} [XX⋯XABC] Is the first to get 「 feasible 」 Section , After we get this feasible interval , We are in accordance with the 「 shrinkage 」 Window principle updates the left border , Get the minimum interval . We actually did some useless operations , When updating the right boundary 「 extend 」 A lot of useless X \rm X X, When updating the left boundary 「 shrinkage 」 Throw away these useless X \rm X X, Did so many useless operations , Just to get a short A B C \rm ABC ABC. you 're right , Actually in s s s in , Some characters we don't care about , We only care about t t t The characters that appear in , Can we preprocess first s s s, Throw those away t t t Characters that do not appear in , And then make a sliding window ? Maybe you'll say , This may lead to X X A B X X C \rm XXABXXC XXABXXC The situation of , The first two can be thrown away when counting the length X \rm X X, But don't throw away the middle X \rm X X, How to solve this problem ? What is the optimized space-time complexity ?
An optimization method : Found during traversal t t t The first of these belongs to t t t character , And make it a sliding window head. When num=0 when , It shows that a window satisfying the meaning of the question has been found so that the characters in t All characters in . It needs to be updated head To remove extra characters , Because the end character must be the demand character and its number is equal to the total demand , Just update head that will do
Code implementation
My initial version :
class Solution {
public:
string minWindow(string s, string t) {
if(s.size() < t.size()) return "";
unordered_map<char, pair<int, int>> hash; // < character ,< Total demand , Total number of existing sliding windows >>
for(auto& it: t){
if(hash.count(it) == 0){
hash[it].first = 1;
hash[it].second = 0;
}else hash[it].first++;
}
// The head, tail and length of the smallest string , The head and tail of the current substring , Traversal pointer , The number of characters that do not exist in the current window
int min_head, min_l, head, ptr, num, size;
head = ptr = 0;
num = t.size();
size = s.size();
min_l = size + 1;
while(ptr < size){
if(hash.count(s[ptr]) != 0){
hash[s[ptr]].second++; // Update the existing total number of sliding windows for this character
if(hash[s[ptr]].second <= hash[s[ptr]].first) num--;
if(num == 0){
/* If a character is encountered, the total number of existing sliding windows > Total demand , Ensure that the header characters hash[s[head]].second == hash[s[head]].first Update head . to update head when , from head Until s The total number of existing sliding windows for a character in is equal to the total number of requirements And take the subscript of the character as the new head */
while(true){
// The total number of existing sliding windows for each character in the sliding window must be greater than or equal to its total number of requirements
if(hash.count(s[head]) != 0){
if(hash[s[head]].second == hash[s[head]].first) break;
else hash[s[head]].second--; // More than its total demand
}
head++;
}
if(ptr-head+1 < min_l){
min_l = ptr-head+1;
min_head = head;
}
}
}
ptr++;
}
return min_l > size? "": s.substr(min_head, min_l);
}
};
My improved version ( Optimize the definition of hash table ):
class Solution {
public:
string minWindow(string s, string t) {
if(s.size() < t.size()) return "";
unordered_map<char, int> hash; // < character , The number of characters required by the sliding window (0 Means equal to the total demand , Greater than 0 It means that..., is still missing , Less than 0 Indicates exceeding )>
for(auto& it: t){
if(hash.count(it) == 0) hash[it] = 1;
else hash[it]++;
}
// The head, tail and length of the smallest string , The head and tail of the current substring , Traversal pointer , The number of characters that do not exist in the current window
int min_head, min_l, head, ptr, num, size;
head = ptr = 0;
num = t.size();
size = s.size();
min_l = size + 1;
while(ptr < size){
if(hash.count(s[ptr]) != 0){
hash[s[ptr]]--; // Update the existing total number of sliding windows for this character
if(hash[s[ptr]] >= 0) num--;
if(num == 0){
/* If a character is encountered, the total number of existing sliding windows > Total demand , Ensure that the header characters hash[s[head]].second == hash[s[head]].first Update head . to update head when , from head Until s The total number of existing sliding windows for a character in is equal to the total number of requirements And take the subscript of the character as the new head */
while(true){
// The total number of existing sliding windows for each character in the sliding window must be greater than or equal to its total number of requirements
if(hash.count(s[head]) != 0){
if(hash[s[head]] == 0) break;
else hash[s[head]]++; // More than its total demand
}
head++;
}
if(ptr-head+1 < min_l){
min_l = ptr-head+1;
min_head = head;
}
}
}
ptr++;
}
return min_l > size? "": s.substr(min_head, min_l);
}
};
My final improved version ( Optimize inner loop ):
class Solution {
public:
string minWindow(string s, string t) {
if(s.size() < t.size()) return "";
unordered_map<char, int> hash; // < character , The number of characters required by the sliding window (0 Means equal to the total demand , Greater than 0 It means that..., is still missing , Less than 0 Indicates exceeding )>
for(auto& it: t){
if(hash.count(it) == 0) hash[it] = 1;
else ++hash[it];
}
// The head, tail and length of the smallest string , The head and tail of the current substring , Traversal pointer , The number of characters that do not exist in the current window
int min_head, min_l, head, ptr, num, size;
head = ptr = 0;
num = t.size();
size = s.size();
min_l = size + 1;
while(ptr < size){
if(hash.count(s[ptr]) != 0){
// Update the existing total number of sliding windows for this character --hash[s[ptr]]
if(--hash[s[ptr]] >= 0) num--;
// When num=0 when , It shows that a window satisfying the meaning of the question has been found so that the characters in t All characters in
// It needs to be updated head To remove extra characters , Because the end character must be the demand character and its number is equal to the total demand , Just update head that will do
while(num == 0){
if(ptr-head+1 < min_l){
min_l = ptr-head+1;
min_head = head;
}
// The total number of existing sliding windows for each character in the sliding window must be greater than or equal to its total number of requirements
// Judge after subtracting the current character , Whether it also meets the requirement that the total number of its existing in the sliding window is not less than the total number of its needs
if(hash.count(s[head]) != 0 && ++hash[s[head]] > 0) num++;
head++;
}
}
ptr++;
}
return min_l > size? "": s.substr(min_head, min_l);
}
};
Leetcode Official explanation :
class Solution {
public:
string minWindow(string s, string t) {
vector<int> chars(128, 0);
vector<bool> flag(128, false);
// Statistics first T Characters in
for(int i = 0; i < t.size(); ++i) {
flag[t[i]] = true;
++chars[t[i]];
}
// Move sliding window , Constantly changing Statistics
int cnt = 0, l = 0, min_l = 0, min_size = s.size() + 1;
for (int r = 0; r < s.size(); ++r) {
if (flag[s[r]]) {
if (--chars[s[r]] >= 0) {
++cnt;
}
// If the current sliding window already contains T All characters in ,
// Then try to l Move right , Get the shortest substring without affecting the result
while (cnt == t.size()) {
if (r - l + 1 < min_size) {
min_l = l;
min_size = r - l + 1;
}
if (flag[s[l]] && ++chars[s[l]] > 0) {
--cnt;
}
++l;
}
}
}
return min_size > s.size()? "": s.substr(min_l, min_size);
}
};
Netizen Youxie :
class Solution {
public:
string minWindow(string s, string t) {
int hash[128] = {
0};
for (auto& c : t) {
++hash[c];
}
int count[128] = {
0};
int cnt = 0;
int beg = 0;
int min_len = INT_MAX;
int min_beg = 0;
for (int i = 0; i < s.size(); ++i) {
char c = s[i];
if (hash[c]) {
++count[c];
if (count[c] <= hash[c]) {
++cnt;
}
}
if (cnt == t.size()) {
for (; beg < i; ++beg) {
char nc = s[beg];
if (hash[nc]) {
if (count[nc] > hash[nc]) {
--count[nc];
continue;
}
break;
}
}
int len = i - beg + 1;
if (len < min_len) {
min_len = len;
min_beg = beg;
}
}
}
return min_len == INT_MAX? "" : s.substr(min_beg, min_len);
}
};
Complexity analysis
Initial version of code analysis :
Time complexity : In the worst case, the left and right pointers are right s s s Go through each element of the , Pairs in hash table s s s Insert each element in 、 Delete once , Yes t t t Insert each element in once . Each time you check whether the row is OK, you will traverse the whole t t t Hash table for , The size of the hash table is related to the size of the character set , Set the character set size to C C C, Then the asymptotic time complexity is O ( C ⋅ ∣ s ∣ + ∣ t ∣ ) O(C\cdot |s| + |t|) O(C⋅∣s∣+∣t∣).
Spatial complexity : Here, two hash tables and several temporary variables are used as auxiliary space , Each hash table can not store key value pairs that exceed the size of the character set at most , We set the character set size to C C C, Then the asymptotic space complexity is O ( C ) O(C) O(C)
Improved version of code analysis :
Time complexity : O ( n ) O(n) O(n), n n n Refers to a string s s s The length of . Although in for Nested in a loop while
loop , But because while
The loop is responsible for moving p t r ptr ptr The pointer , And p t r ptr ptr It only moves from left to right once , So the total time complexity is still O ( n ) O(n) O(n).
Spatial complexity : Here, a hash table and several temporary variables are used as auxiliary space , Each hash table can not store key value pairs that exceed the size of the character set at most , We set the character set size to C C C, Then the asymptotic space complexity is O ( C ) O(C) O(C)
边栏推荐
猜你喜欢
Pain points and solutions of M1 notebook home office | community essay solicitation
Yunhe enmo Guoqiang, identifiez - le, saisissez - le, avant l'ébullition de la base de données nationale
漫画安全HIDS、EDR、NDR、XDR
Set up security groups, record domain names, and apply for SSL certificates
【微信小程序】认识小程序项目的基本组成结构
二叉搜索树 230. 二叉搜索树中第K小的元素 1038. 从二叉搜索树到更大和树
Simple understanding of B tree and b+ tree
小程序插件接入、开发与注意事项
Create an API rapid development platform, awesome!
Yunhe enmo, gaiguoqiang, identify it and grasp it before the domestic database boils
随机推荐
Ingenious application of golang generics to prevent null pointer errors of variables and structural fields
LC:最大子数组和
Solution to version conflict of flutter plug-in
After crossing, she said that the multiverse really exists
二叉树的序列化 力扣 297. 二叉树的序列化与反序列化 652. 寻找重复的子树
Set up enterprise NTP time server
Bee common configuration
modelsim的TCL脚本的define incdir命令解析
招商证券靠谱吗?开股票账户安全吗?
【一起上水硕系列】Day 8
Et la tarte aux framboises 4? Quels sont les jeux possibles?
Gradle连载7-配置签名
FPGA开发(1)——串口通信
Solr basic operation 4
Xutils3 transfer set
Why is JSX syntax so popular?
我想知道今天还可以开户么?另外想问,现在在线开户安全么?
剑指 Offer 14- I. 剪绳子
FPGA开发(2)——IIC通信
Binary search tree 230 The element with the smallest K in the binary search tree 1038 From binary search tree to larger sum tree