滑动窗口解决相关问题

131 阅读1分钟

使用滑动窗口,双指针解决问题

最小覆盖子串【leetcode-76】

题目描述

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。

注意:

对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。 如果 s 中存在这样的子串,我们保证它是唯一的答案。

运行效率

双指针.png

代码如下

function minWindow(s: string, t: string): string {
  const [tset, tmap] = initT(t);
  const str = initS(s, tset);

  //测试str
  // console.log("----test----", testT(str, s));

  let res: [number, number] = [0, Infinity];
  let temp = new Map();
  let okCount = 0;
  let pre = 0;
  let end = 0;
  while (end < str.length) {
    while (okCount !== tset.size && end < str.length) {
      const key = s.charAt(str[end]);
      temp.set(key, (temp.get(key) ?? 0) + 1);
      if (temp.get(key) === tmap.get(key)) {
        okCount++;
      }
      end++;
    }

    while (okCount === tset.size && pre < end) {
      const key = s.charAt(str[pre]);
      temp.set(key, temp.get(key) - 1);
      if (temp.get(key) < tmap.get(key)) {
        //记录结果
        res =
          res[1] - res[0] > str[end - 1] - str[pre]
            ? [str[pre], str[end - 1] + 1]
            : res;
        okCount--;
      }
      pre++;
    }
  }

  return res[1] === Infinity ? "" : s.substring(res[0], res[1]);

  function initS(s: string, tSet: Set<string>): number[] {
    const str: number[] = [];
    for (let i = 0; i < s.length; i++) {
      const key = s.charAt(i);
      if (tSet.has(key)) {
        str.push(i);
      }
    }
    return str;
  }

  function initT(t: string): [Set<string>, Map<string, number>] {
    const set = new Set<string>();
    const map = new Map();
    for (let i = 0; i < t.length; i++) {
      const key = t.charAt(i);
      map.set(key, (map.get(key) ?? 0) + 1);
      set.add(key);
    }
    return [set, map];
  }
}

function testT(str: number[], s: string) {
  return str.reduce((acc, i) => acc + s.charAt(i), "");
}

const res = minWindow("ADOBECODEBANC", "ABC");

const res1 = minWindow("a", "a");

const res2 = minWindow("a", "aa");

const res3 = minWindow("ab", "a");
debugger;