算法题-数组-76-最小覆盖子串

38 阅读1分钟

76-最小覆盖子串

题目描述

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

注意:

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

示例 1:

输入: s = "ADOBECODEBANC", t = "ABC"
输出: "BANC"

示例 2:

输入: s = "a", t = "a"
输出: "a"

示例 3:

输入: s = "a", t = "aa"
输出: ""

分析

利用滑动窗口,left不动,right向右移动,直至二者之间的子串满足要求,即包含t的所有字符。此时开始滑动窗口,right不动,如果left右移一步之后子串仍满足要求则进行右移,否则的话left右移一步之后开始移动right。直至right到达字符串s的末尾。

题解

/**
 * @param {string} s
 * @param {string} t
 * @return {string}
 */
var minWindow = function(s, t) {
  let need = {};
  let needType = 0;
  let start = s.length;
  let minLen = s.length + 1;
  for(let i=0; i<t.length; i++) {
    if(need[t[i]]) {
      need[t[i]] += 1;
    } else {
      need[t[i]] = 1;
      needType++;
    }
  }
  let l=r=0;

  for(; r<s.length; r++) {
    let newWord = s[r];                                 // 新字符
    if(need[newWord] !== undefined) need[newWord]--     // 新字符在need中,那么可以减一
    if(need[newWord] == 0) needType--                   // 如果经过上一步之后该字符的需求数为0,那么说明该Type不需要了
    while(needType==0) {                   // needType==0 即当前子串满足要求,接下来将左指针右移直到不满足题目要求,也就是 needType>0
      if(r-l+1<minLen) {                   // 如果碰到更短的子串,更新返回量
        start = l;
        minLen = r-l+1;
      }
      let leftWord = s[l];                 // 旧字符
      if(need[leftWord] !== undefined) need[leftWord]++ // 丢弃了need中的字符
      if(need[leftWord] > 0) needType++ // 缺失种类加一
      l++;
    }
  }
  if(start==s.length) return ''
  return s.substring(start, start+minLen);
};

分析

时间复杂度:O(n)

空间复杂度:O(k) 两个字符串的长度

难点

双指针,滑动窗口