串联所有单词的子串

105 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情

30. 串联所有单词的子串 - 力扣(Leetcode)

给定一个字符串 s 和一些 长度相同 的单词 words 。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。

注意子串要与 words 中的单词完全匹配,中间不能有其他字符 ,但不需要考虑 words 中单词串联的顺序。

示例 1:

输入: s = "barfoothefoobarman", words = ["foo","bar"]
输出: [0,9]
解释:
从索引 0 和 9 开始的子串分别是 "barfoo" 和 "foobar" 。
输出的顺序不重要, [9,0] 也是有效答案。

示例 2:

输入: s = "wordgoodgoodgoodbestword", words = ["word","good","best","word"]
输出: []

示例 3:

输入: s = "barfoofoobarthefoobarman", words = ["bar","foo","the"]
输出: [6,9,12]

提示:

  • 1 <= s.length <= 10^4
  • s 由小写英文字母组成
  • 1 <= words.length <= 5000
  • 1 <= words[i].length <= 30
  • words[i] 由小写英文字母组成

思路

本题可以用滑动窗口求解。设words的长度为mwords中每个单词的长度为n。首先将s划分为单词组,每个单词长度为n(首尾单词除外),共有n种划分方法。划分好单词组后就可以用滑动窗口求解了。

一个窗口中包含s中的m个单词,用一个哈希表map来存储窗口中单词出现次数和words中单词次数的差。初始化时,遍历words中每个单词,出现一次mapword1,然后遍历窗口中每一个单词,出现一次map中对应的word1,当map中所有word的值都为0时,就是恰好匹配words中的所有单词了。滑动窗口时,划出的word1,划入的加1

解题

/**
 * @param {string} s
 * @param {string[]} words
 * @return {number[]}
 */
var findSubstring = function (s, words) {
  const res = [];
  const m = words.length;
  const n = words[0].length;
  const total = m * n;
  const len = s.length;
  if (total > len) return res;
  const split = (s, start) => {
    const arr = [""];
    let end = start + n;
    while (end <= len) {
      arr.push(s.substring(start, end));
      start = end;
      end += n;
    }
    return arr;
  };
  const counter = (map, word, count) => {
    count += map.get(word) || 0;
    if (count === 0) {
      map.delete(word);
    } else {
      map.set(word, count);
    }
  };
  for (let i = 0; i < n; i++) {
    if (i + total > len) break;
    const map = new Map();
    let arrs = split(s, i);
    for (let j = 0; j < m; j++) {
      counter(map, words[j], -1);
    }
    for (let j = 0; j < m; j++) {
      counter(map, arrs[j], 1);
    }
    for (let j = m; j < arrs.length; j++) {
      counter(map, arrs[j - m], -1);
      counter(map, arrs[j], 1);
      if (map.size === 0) {
        res.push(i + (j - m) * n);
      }
    }
  }
  return res;
};