经典滑动窗口

:::success

](https://leetcode-cn.com/problems/minimum-operations-to-reduce-x-to-zero/)

字符串问题

剑指 Offer 48. 最长不含重复字符的子字符串

case 1: “abcabcbb” => 3
case 2: “bbbbb” => 1

滑动窗口+哈希表

  1. var lengthOfLongestSubstring = function(s) {
  2. // 滑动窗口+哈希表
  3. // if (s.length < 2) return s.length;
  4. let left = 0;
  5. let hashTable = new Map();
  6. let res = 0;
  7. for (let right = 0; right < s.length; right++) {
  8. let cur = s.charAt(right)
  9. if (!hashTable.has(cur) || left > hashTable.get(cur)) {
  10. res = Math.max(res, right - left + 1)
  11. } else if (left <= hashTable.get(cur)) {
  12. left = hashTable.get(cur) + 1
  13. }
  14. hashTable.set(cur, right)
  15. }
  16. return res
  17. };

76. 最小覆盖子串

image.png
辅助空间 (128是ASCII值总量, 实际97-122为存放a-z数量)

  • need 标记目标字符
  • window 标记滑动窗口中的字符

两层循环:

  • 外侧负责右指针
    • 出口,指针移动至右边界
  • 内侧负责左指针
    • 出口, 窗口包含目标字符

目标: 右指针右移扩大窗口
左指针右移缩小窗口
移动指针均对window产生影响

function minWindow(s: string, t: string): string {
    let n1 = s.length, n2 = t.length;
    if (n1 < n2) return '';
    let need = new Array(128).fill(0);
    let window = new Array(128).fill(0);
    for (let i = 0; i < n2; ++i) {
        ++need[t.charCodeAt(i)];
    }

    let left = 0, right = 0;
    let res = '';
    let count = 0;
    let min = n1 + 1;
    // 移动右指针
    while (right < n1) {
        let cur = s.charCodeAt(right);
        ++window[cur];
        if (need[cur] > 0 && need[cur] >= window[cur]) {
            ++count;
        }
        // 尽可能的移动左指针
        while (count == n2) {
            cur = s.charCodeAt(left);
            if (need[cur] > 0 && need[cur] >= window[cur]) {
                --count;
            }
            if (right - left + 1 < min) {
                min = right - left + 1;
                res = s.slice(left, right + 1);
            }
            --window[cur];
            ++left;
        }
        ++right;
    }
    return res;
};

接水问题

11. 盛最多水的容器

image.png

var maxArea = function(height) {
    let max = 0;
    let left = 0, right = height.length -1;
    while (left < right) {
        let area = (right - left) * Math.min(height[left], height[right]);
        max = Math.max(max, area);
        if (height[left] < height[right]) {
            left++;
        } else {
            right--;
        }
    }
    return max;
};

42. 接雨水 [字节]

左右指针+左右最大值
image.pngimage.png

var trap = function(height) {
    let sum = 0;
    let left = 0, right = height.length - 1;
    let maxLeft = 0, maxRight = 0;
    while (left < right) {
        if (height[left] < height[right]) {
            // move left
            if (height[left] >= maxLeft) {
                maxLeft = height[left];
            } else {
                sum += maxLeft - height[left]
            }
            left++;
        } else {
            // move right
            if (height[right] >= maxRight) {
                maxRight = height[right];
            } else {
                sum += maxRight - height[right]
            }
            right--;
        }
    }
    return sum;
};