串联所有单词的子串 |刷题打卡

196 阅读2分钟

掘金团队号上线,助你 Offer 临门! 点击 查看大厂春招职位

一、题目描述:

给定一个字符串 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-cn.com/problems/su…

二、思路分析:

滑块、或者叫窗口搜索。大致意思是定义两个指针,start、end,我们的最终目的是希望,从start至end能恰好包含所有的单词, 即,所有单词可以串联成start至end的字符串。

初始化的时候start和end都是指向0,定义一个count,记录窗口(start,end)内的单词个数。

如果 end + word.length 没有超过 s.length,说明end后面还有可用的单词,然后开始循环

如果s的子串 [end,end+word.length),是一个单词,那么end移动到end+word.length,单词个数加1,

如果count与总的单词个数相等,说明找到一个答案。

如果s的子串 [end,end+word.length),不是一个单词,start后移,end = start,单词个数清零。

关于重复单词的问题:

定义两个map集合,一个用于记录原始的单词与个数的映射,一个用于记录滑块窗口的单词与个数的映射。

每次移动end的时候,判断一下滑块里的当前单词个数是否超出了原始的单词个数,超出就移动start,临时数据清零

三、AC 代码:

   public List<Integer> findSubstring(String s, String[] words) {
        if(s.length() == 0 || words.length == 0){
            return new ArrayList<>();
        }
        Map<String,Integer> wordMap = new HashMap<>();
        for (String word:words) {
            if (wordMap.containsKey(word)){
                wordMap.put(word,wordMap.get(word)+1);
            }else {
                wordMap.put(word,1);
            }
        }

        Map<String,Integer> temp = new HashMap<>();
        List<Integer> ans = new ArrayList<>();
        int start = 0;
        int end = 0;
        int wordLength = words[0].length();
        int arrLength = words.length;
        int tempArrLength = 0;
        while (end+wordLength<s.length()+1){
            String tempWord = s.substring(end,end+wordLength);

            Integer value = wordMap.get(tempWord);
            Integer tempValue = temp.get(tempWord);

            if (value!=null&&(tempValue == null || tempValue<value)){
                if (tempValue == null){
                    tempValue = 0;
                }
                temp.put(tempWord,tempValue+1);
                end+=wordLength;
                tempArrLength++;
            }else {
                start++;
                end = start;
                tempArrLength = 0;
                temp.clear();
            }
            if (tempArrLength == arrLength){
                ans.add(start);
                start++;
                end = start;
                tempArrLength = 0;
                temp.clear();
            }
        }
        return ans;
    }