返回
最小覆盖子串:JS算法解读与实现
前端
2023-09-09 02:14:28
- 最小覆盖子串概述
最小覆盖子串是字符串s中包含字符串t所有字符的最小子串,若不存在,则返回空字符串。它在字符串匹配、子串查找和自然语言处理等领域有着广泛的应用。
2. 算法原理
最小覆盖子串的算法原理是基于贪心算法。算法流程如下:
- 初始化一个滑动窗口,窗口大小为t的长度。
- 从字符串s的第一个字符开始,将字符添加到滑动窗口中,直到窗口中包含t的所有字符。
- 移动滑动窗口,将窗口右边界向右移动一位,同时将窗口左边界向右移动一位,直到窗口中不再包含t的所有字符。
- 重复步骤2和步骤3,直到窗口右边界到达字符串s的最后一个字符。
- 记录下窗口大小最小的子串,即为最小覆盖子串。
3. JS实现
/**
* 寻找字符串s中包含字符串t所有字符的最小子串
* @param {string} s
* @param {string} t
* @returns {string}
*/
const minWindow = (s, t) => {
if (s.length < t.length) {
return "";
}
const tMap = {};
for (let i = 0; i < t.length; i++) {
const char = t[i];
tMap[char] = (tMap[char] || 0) + 1;
}
let minLen = Infinity;
let minStart = 0;
let windowStart = 0;
let windowEnd = 0;
let matched = 0;
while (windowEnd < s.length) {
const char = s[windowEnd];
if (char in tMap) {
tMap[char]--;
if (tMap[char] >= 0) {
matched++;
}
}
while (matched === t.length) {
if (windowEnd - windowStart + 1 < minLen) {
minLen = windowEnd - windowStart + 1;
minStart = windowStart;
}
const leftChar = s[windowStart];
if (leftChar in tMap) {
tMap[leftChar]++;
if (tMap[leftChar] > 0) {
matched--;
}
}
windowStart++;
}
windowEnd++;
}
return minLen === Infinity ? "" : s.substring(minStart, minStart + minLen);
};
4. 算法复杂度分析
算法的时间复杂度为O(s + t),其中s是字符串s的长度,t是字符串t的长度。算法需要遍历字符串s一次,并在每次遍历中检查窗口中是否包含t的所有字符,因此时间复杂度为O(s)。此外,算法还需要对字符串t中的每个字符进行计数,因此时间复杂度为O(t)。因此,算法的总时间复杂度为O(s + t)。
5. 常见面试题
最小覆盖子串问题经常出现在技术面试中,以下是几个常见的面试题:
- 寻找字符串s中包含字符串t所有字符的最小子串。
- 寻找字符串s中包含字符串t所有字符的最长子串。
- 寻找字符串s中包含字符串t所有字符的最少重复次数。
6. 总结
最小覆盖子串算法是一种贪心算法,它可以高效地找到字符串s中包含字符串t所有字符的最小子串。算法原理简单,易于理解和实现。它在字符串匹配、子串查找和自然语言处理等领域有着广泛的应用。通过本文的学习,希望您对最小覆盖子串算法有了更深入的了解。