给定一个字符串 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”]
    输出:[]

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/substring-with-concatenation-of-all-words

    思路:

    • 维护单词长度个滑动窗口,每个单词长度相同,所以每次滑动固定长度。
    • 如果当前单词不在words中,说明这个窗口内的内容无法继续匹配了,重置计数器和左指针。
    • 在其中时需要考虑如果该单词个数大于words中个数时,需要移动左指针,以及将最左侧单词计数减一。
    • 考虑一些边界条件,例如s长度比words中单词长度短,s或words为空。

    复杂度分析:
    时间复杂度O(n)
    空间复杂度O(n)

    1. /**
    2. * @param {string} s
    3. * @param {string[]} words
    4. * @return {number[]}
    5. */
    6. var findSubstring = function(s, words) {
    7. if(words.length===0 || s.length === 0) return [];
    8. const Counter = (array)=>{
    9. let map = new Map();
    10. for(let i = 0;array && i < array.length; i++){
    11. let tmp = map.get(array[i]);
    12. if(tmp !== undefined){
    13. map.set(array[i],tmp+1);
    14. }else{
    15. map.set(array[i],1);
    16. }
    17. }
    18. return map;
    19. }
    20. let word_num = words.length;
    21. let one_word = words[0].length;
    22. let n = s.length;
    23. if(n < one_word) return [];
    24. let ans = [];
    25. words = Counter(words);
    26. for(let i = 0;i < one_word ;i++){
    27. let left = i;
    28. let right = i;
    29. let cur_map = Counter();
    30. let cnt = 0;
    31. while(right + one_word <= n){
    32. let w = s.slice(right,right+one_word);
    33. right += one_word;
    34. if(words.get(w)){
    35. cnt += 1;
    36. if(cur_map.get(w)){
    37. cur_map.set(w,cur_map.get(w)+1);
    38. }else{
    39. cur_map.set(w,1);
    40. }
    41. while(cur_map.get(w) > words.get(w)){
    42. let left_w = s.slice(left,left+one_word);
    43. left += one_word;
    44. if(cur_map.get(left_w)){
    45. cur_map.set(left_w,cur_map.get(left_w)-1);
    46. }else{
    47. cur_map.set(left_w,0);
    48. }
    49. cnt -=1;
    50. }
    51. if(cnt === word_num) ans.push(left)
    52. }else{
    53. cnt = 0;
    54. left = right;
    55. cur_map.clear();
    56. }
    57. }
    58. }
    59. return ans;
    60. };