[暴力、滑动窗口] 30. 串联所有单词的子串

112 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第25天,点击查看活动详情

每日刷题 2022.06.23

题目

  • 给定一个字符串 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] 由小写英文字母组成

解题思路

  • 每次看到题目类型,困难,就想睡大觉,hhhh。今天不一样,思考了一下,感觉暴力思路应该也能过,就没有查看题解,硬着头皮做过了,hhhhhh, o( ̄▽ ̄)ブ
  • 分析题意:需要输出能够在s字符串中找到word连续的下标,并且word组成的顺序可以是随意的,但是一定要是连续的。
  • 注意⚠️:因为有可能word中会出现多个相同的字符串,那么就不能只判断这个字符串是否出现过,而是需要判断字符串出现的次数是否满足,如果有一个不满足,那么从当前下标开始的记录,就不成立;反之,如果对于word中的每一个元素都满足,并且所有满足的字符串个数是刚好等于word的长度的话,那么就说明找到了一个连续的符合的字符串,从而在ans数组中记录下当前的下标。
  • 以此重复执行,知道s的每一个元素都被查找完。
  • 注意⚠️:题目中给出说word中的每一个字符串都是等长的(记为n),因此可以每次在s字符串中判断的时候,直接截取长度n,进行比对。

AC代码

/**
 * @param {string} s
 * @param {string[]} words
 * @return {number[]}
 */
var findSubstring = function(s, words) {
  // 可以循环遍历对每一个元素进行查找,使用一个vis数组记录,每个是否都被找到过,找到的话,就不能找,同时数组的长度记录,判断是否数组中的元素全部被找到
  // 10 ^4 * 5 * 10 ^ 3 = 5 * 10 ^7
  let w = words, n = words.length, ns = s.length, len = w[0].length,ans = [];
  if(ns < len) return ans;
  let vis = new Array(n).fill(0);
  for(let i = 0; i < n; i++) {
    let index = w.indexOf(w[i]);
    vis[index]++;
  }
  let contra = new Array(n).fill(0);
  // console.log('len:::', ns,len)
  //每次截取固定长度来进行匹配
  for(let i = 0; i < ns - len + 1; i++) {
    // console.log(s.substr(i, len));
    let num = 0;
    contra = new Array(n).fill(0);
    for(let j = i; j < ns - len + 1;) {
      let cur = s.substr(j, len), idx = w.indexOf(cur);
      // console.log('cur:::', cur, idx, contra)
      if(idx == -1) break;  
      if(idx != -1) {
        contra[idx]++;
        num++;
      }
      if(contra[idx] > vis[idx]) break;
      if(num == n) {
        ans.push(i);
      }
      j += len;
      // console.log('end::', j, ns - len + 1)
    }
  }
  return ans;
};