30. 串联所有单词的子串

一、题目

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

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

示例 1:

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

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

二、解答

2.1方法一:map+滑动窗口
public List findSubstring(String s, String[] words) {
        List result = new ArrayList();
        if (s.length() == 0 || words.length == 0 || words[0].equals("")){
            return result;
        }

        int sLen = s.length();
        int wLen = words[0].length();
        int len = words.length;

        //记录字串与个数
        Map wordMap = new HashMap();
        for(String w : words){
            if (wordMap.containsKey(w)){
                wordMap.put(w,wordMap.get(w) + 1);
                continue;
            }

            wordMap.put(w,1);
        }

        //滑动窗口匹配
        for (int i = 0; i < wLen; i++){
            //滑动窗口map
            Map sMap = new HashMap();
            //滑动窗口的开始位置
            int first = i;
            //当前字符串的起始位置
            int start = i;
            //当前字符串的结束位置
            int end = start + wLen;
            //滑动窗口内的字符串个数
            int cnt = 0;
            
            while (end <= sLen){
                //滑动窗口map的字符串个数超过words数组个数时候,清除第一个字符串
                if (cnt > 0 && cnt >= len){
                    String key = s.substring(first,first + wLen);
                    if (sMap.containsKey(key)){
                        if (sMap.get(key) == 1){
                            sMap.remove(key);
                        }else {
                            sMap.put(key,sMap.get(key) - 1);
                        }
                    }

                    first += wLen;
                }

                String key = s.substring(start,end);
                //滑动窗口map添加记录
                if (wordMap.containsKey(key)){
                    if (sMap.containsKey(key)){
                        sMap.put(key,sMap.get(key) + 1);
                    }else {
                        sMap.put(key,1);
                    }
                }else {
                    //发现存在不在words数组的元素,清空滑动窗口map
                    sMap.clear();
                    //滑动窗口从后面开始计算
                    first = start + wLen;
                    //滑动窗口cnt归0,但是本循环后面+1了
                    cnt = -1;
                }

                //对比窗口与目标words数组是否相等
                if (isEquals(wordMap,sMap)){
                    result.add(first);
                }

                start += wLen;
                end = start + wLen;
                cnt++;
            }
        }

        return result;
    }

    public boolean isEquals(Map l,Map r){
        if (l == null || l.size() == 0 || r == null || r.size() == 0 || r.size() != l.size()){
            return false;
        }

        for (Map.Entry map : l.entrySet()){
            if (map.getValue() != r.get(map.getKey())){
                return false;
            }
        }

        return true;
    }

你可能感兴趣的:(30. 串联所有单词的子串)