diff --git a/content/posts/2024/02/0214.md b/content/posts/2024/02/0214.md new file mode 100644 index 0000000..41ab44c --- /dev/null +++ b/content/posts/2024/02/0214.md @@ -0,0 +1,95 @@ +--- +title: '0214-滑动窗口' +date: 2024-02-14T20:36:50+08:00 +lastmod: +tags: [] +series: [] +categories: [] +--- + +## 大体算法 + +```js +function slideWindow() { + // 前后快慢双指针 + let left = 0 + let right = 0 + /** 具体的条件逻辑根据实际问题实际处理,多做练习 */ + while(slide condition) { + window.push(s[left]) // s 为总数据(字符串、数组) + right++ + while(shrink condition) { + window.shift(s[left]) + left++ + } + } +} +``` + +> 滑动窗口的算法时间复杂度为 `O(n)`,适用于处理大型数据集 + +## 练习 + +### 最小覆盖子串 lc.76 + +```js +/** + * @param {string} s + * @param {string} t + * @return {string} + */ +var minWindow = function (s, t) { + if (s.length < t.length) return '' + const tMap = {} + for (const char of t) { + tMap[char] = tMap[char] ? ++tMap[char] : 1 + } + const keyLength = Object.keys(tMap).length + let left = 0 + let right = 0 + const window = {} + let validCharCount = 0 + let minStr = '' + while (right < s.length) { + const c = s[right] + window[c] = window[c] ? ++window[c] : 1 + if (window[c] === tMap[c]) validCharCount++ + right++ + + while (validCharCount === keyLength) { + const d = s[left] + if (window[d] === tMap[d]) { + validCharCount-- + // 分析出,此时字符串区间 应当为[left, right),因为 此时 right 已经++,left 还未++ + const str = s.substring(left, right) + if (!minStr) { + minStr = str + } else { + minStr = str.length < minStr.length ? str : minStr + } + } + window[d] = window[d] - 1 + left++ + } + } + return minStr +} +``` + +--- + +## 应用 + +滑动窗口算法适用于解决以下类型的问题: + +- 查找最大子数组和 +- 查找具有 K 个不同字符的最长子串 +- 查找具有 K 个不同字符的最短子串 +- 查找具有特定条件的最长子串或子数组 +- 查找具有特定条件的最短子串或子数组 +- 查找连续 1 的最大序列长度(可以在允许将最多 K 个 0 替换为 1 的情况下) +- 查找具有特定和的子数组 +- 查找具有不同元素的子数组 +- 查找具有特定条件的最大或最小子数组 + +滑动窗口算法通常用于解决需要在数组或字符串上维护一个固定大小的窗口,并在窗口内执行特定操作或计算的问题。这种算法技术可以有效降低时间复杂度,通常为 `O(n)`,适用于处理大型数据集。