Given two strings s and t of lengths m and n respectively, return the minimum window substring of s such that every character in t (including duplicates) is included in the window. If there is no such substring, return the empty string "".
The testcases will be generated such that the answer is unique.
Example 1:
Input: s = "ADOBECODEBANC", t = "ABC" Output: "BANC" Explanation: The minimum window substring "BANC" includes 'A', 'B', and 'C' from string t.
Example 2:
Input: s = "a", t = "a" Output: "a" Explanation: The entire string s is the minimum window.
Example 3:
Input: s = "a", t = "aa" Output: "" Explanation: Both 'a's from t must be included in the window. Since the largest window of s only has one 'a', return empty string.
Constraints:
m == s.lengthn == t.length1 <= m, n <= 105sandtconsist of uppercase and lowercase English letters.
Follow up: Could you find an algorithm that runs in O(m + n) time?
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。
注意:
- 对于
t中重复字符,我们寻找的子字符串中该字符数量必须不少于t中该字符数量。 - 如果
s中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入:s = "ADOBECODEBANC", t = "ABC" 输出:"BANC" 解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。
示例 2:
输入:s = "a", t = "a" 输出:"a" 解释:整个字符串 s 是最小覆盖子串。
示例 3:
输入: s = "a", t = "aa" 输出: "" 解释: t 中两个字符 'a' 均应包含在 s 的子串中, 因此没有符合条件的子字符串,返回空字符串。
提示:
m == s.lengthn == t.length1 <= m, n <= 105s和t由英文字母组成
进阶:你能设计一个在
o(m+n) 时间内解决此问题的算法吗?
| Language | Runtime | Memory | Submission Time |
|---|---|---|---|
| typescript | 1056 ms | 50.1 MB | 2022/05/30 17:50 |
function minWindow(s: string, t: string): string {
if (s.length < t.length) {
return '';
}
const tMap: Record<string, number> = {};
let min = +Infinity;
let res = '';
let window = '';
const windowMap: Record<string, number> = {};
for (let i = 0; i < t.length; i++) {
tMap[t[i]] = tMap[t[i]] ? tMap[t[i]] + 1 : 1;
}
function isValid(): boolean {
let flag = true;
const iter = Object.entries(tMap);
for (let i = 0; i < iter.length; i++) {
const [k, v] = iter[i];
if (windowMap[k] === undefined) {
flag = false;
break;
}
if (v > windowMap[k]) {
flag = false;
break;
}
}
return flag;
}
let start = 0, end = 1;
window = s.slice(start, end);
windowMap[window[0]] = 1;
while (start <= end && end <= s.length) {
if (isValid()) {
if (window.length < min) {
res = window;
min = window.length;
}
const cnt = windowMap[window[0]];
windowMap[window[0]] = cnt - 1;
start++;
window = s.slice(start, end);
} else {
end++;
window = s.slice(start, end);
const last = window[window.length - 1];
windowMap[last] = windowMap[last] ? windowMap[last] + 1 : 1;
}
}
return res;
};参考官方题解的滑动窗口法写的解法:
function minWindow(s: string, t: string): string {
if (s.length < t.length) {
return '';
}
const tMap: Record<string, number> = {};
let min = +Infinity;
let res = '';
let window = '';
const sMap: Record<string, number> = {};
for (let i = 0; i < t.length; i++) {
tMap[t[i]] = tMap[t[i]] ? tMap[t[i]] + 1 : 1;
}
function isValid(): boolean {
let flag = true;
const iter = Object.entries(tMap);
for (let i = 0; i < iter.length; i++) {
const [k, v] = iter[i];
if (sMap[k] === undefined) {
flag = false;
break;
}
if (v > sMap[k]) {
flag = false;
break;
}
}
return flag;
}
let start = 0, end = 1;
window = s.slice(start, end);
sMap[window[0]] = 1;
while (start <= end && end <= s.length) {
if (isValid()) {
if (window.length < min) {
res = window;
min = window.length;
}
const cnt = sMap[window[0]];
sMap[window[0]] = cnt - 1;
start++;
window = s.slice(start, end);
} else {
end++;
window = s.slice(start, end);
const last = window[window.length - 1];
sMap[last] = sMap[last] ? sMap[last] + 1 : 1;
}
}
return res;
};讲道理时间复杂度是一样的,我也不知道为什么执行用时那么长...
时间复杂度:最坏情况下左右指针对
$s$ 的每个元素各遍历一遍,哈希表中对$s$ 中的每个元素各插入、删除一次,对$t$ 中的元素各插入一次。每次检查是否可行会遍历整个$t$ 的哈希表,哈希表的大小与字符集的大小有关,设字符集大小为$C$ ,则渐进时间复杂度为$O(C⋅∣s∣+∣t∣)$ 。 空间复杂度:这里用了两张哈希表作为辅助空间,每张哈希表最多不会存放超过字符集大小的键值对,我们设字符集大小为$C$ ,则渐进空间复杂度为$O(C)$ 。