0
点赞
收藏
分享

微信扫一扫

[数组]BM90 最小覆盖子串-中等

​​BM90 最小覆盖子串​​

知识点​​哈希​​​​双指针​​​​字符串​​

描述


给出两个字符串 s 和 t,要求在 s 中找出最短的包含 t 中所有字符的连续子串。

数据范围:[数组]BM90 最小覆盖子串-中等_hash表,保证s和t字符串中仅包含大小写英文字母要求: 时间复杂度 [数组]BM90 最小覆盖子串-中等_滑动窗口_02例如:

[数组]BM90 最小覆盖子串-中等_字符串_03
[数组]BM90 最小覆盖子串-中等_滑动窗口_04
找出的最短子串为[数组]BM90 最小覆盖子串-中等_字符串_05.

注意:
如果 s 中没有包含 t 中所有字符的子串,返回空字符串 “”;
满足条件的子串可能有很多,但是题目保证满足条件的最短的子串唯一。

示例1

输入:

"XDOYEZODEYXNZ","XYZ"

复制返回值:

"YXNZ"

复制

示例2

输入:

"abcAbA","AA"

复制返回值:

"AbA"

题解

思路:

  1. 假设要在字符串s中找字符串t,使用一个hash表n存放t每个字符出现的次数
  2. 遍历整个字符串s,使用hash表m记录某个区间中在字符串t中的字符出现的次数
  3. 使用一个计数器count标记在字符串s的某个区间中出现字符的种类数,对于在t中的某个字符x,只有大于m[x] >= n[x]的时候才计数一次,且在该区间只记一次,因此使用一个辅助hash表b来左标记
  4. 当索引到达i的时候,如果s[i]在n中,则对m[s[i]]递增,如果m[s[i]]的值大于等于n[s[i]]则可以对count累加,同时设置b[s[i]] = false
  5. 如果count == n.size(),那么表示所有的条件都满足了,让缩小左边界的同时对m[s[i]]递减,直到count < n.size(),此时左右边界是在该区间的最小子串长度
  6. 遍历完整个数组,当长度变小的时候,更新长度

注意:

实际上,可以讲代码中的m和n合并使用同一个hash表,前面初始化n的时候初始化为负值,后面统计key的时候将对应的hash值递增,然后边界条件就是和0比较了。

代码如下:

#include <bits/stdc++.h>

std::string minWindow(std::string S, std::string T)
{
int left = 0;
size_t len = S.npos;
int ans_start = 0;
std::unordered_map<char, int> m;
std::unordered_map<char, int> n;
std::unordered_map<char, bool> b;
int count = 0;

for (int i = 0; i < T.size(); ++i)
{
n[T[i]]++;
b[T[i]] = false;
}
for (int i = 0; i < S.size(); ++i)
{
auto x = S[i];
if (n.find(x) == n.end())
{
continue;
}
m[x]++;
if (m[x] >= n[x] && !b[x])
{
count++;
b[x] = true;
}

if (count == n.size())
{
int right = i;
// 缩小左边界,直到某个key出现的次数刚好为要求的最小次数
while (left < right)
{
if (m.find(S[left]) != m.end())
{
m[S[left]]--;
if (m[S[left]] >= n[S[left]])
{
left++;
continue;
}
else
{
count--;
b[S[left]] = false;
break;
}
}
left++;
}
// 这部分注释是代码可以省略,因为count == n.size()一定是s[i]对某个key累加后刚好满足的
// 去掉s[i]则count < n.size()
// while (right > left)
// {
// if (m.find(S[right]) != m.end())
// {
// if (m[S[right]] > n[S[right]])
// {
// m[S[right]]--;
// count--;
// right--;
// continue;
// }
// else
// {
// b[S[right]] = false;
// break;
// }
// }
// right--;
// }
if (right - left + 1 < len)
{
ans_start = left;
len = right - left + 1;
}
left++;
}
}

if (len == S.npos)
{
return "";
}
return S.substr(ans_start, len);
}
举报

相关推荐

0 条评论