/**
     * 
     * 给定一个字符串 s 和一些 长度相同 的单词 words 。
     * 找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。
     * <p>
     * 注意子串要与 words 中的单词完全匹配,中间不能有其他字符 ,
     * 但不需要考虑 words 中单词串联的顺序
     * 
     */
public List<Integer> findSubstring(String s, String[] words) {
        //定义集合保存索引
        ArrayList<Integer> list = new ArrayList<>();
        //字符串数组的长度
        int strsLen = words.length;
        //字符串数组中每个字符串的长度
        int wordLen = words[0].length();
        //则滑动窗口的长度为 strsLen * wordLen
        int windowLen = strsLen * wordLen;
        //将字符串数组中字符串存储到哈希表中,key存储字符串,value存储字符串出现的次数
        HashMap<String, Integer> map = new HashMap<>();
        for (String word : words) {
            //如果键存在,返回键所映射的值,如果键不存在返回默认值
            Integer value = map.getOrDefault(word, 0);
            map.put(word, value + 1);
        }
        //然后把一个窗口中的字符串拆分成子串存储到哈希表中,如果哈希表相同,则匹配
        //字符串s的长度
        int strLen = s.length();
        for (int i = 0; i < strLen - windowLen + 1; i ++) {
            //拿到每一个窗口,并将窗口中的字符串切割为成为为wordLen的子串
            String window = s.substring(i, windowLen + i);
            String[] subStr = new String[strsLen];
            int k = 0;
            for (int j = 0; j < windowLen - wordLen + 1; j += wordLen) {
                subStr[k] = window.substring(j,j + wordLen);
                k++;
            }
            //存入哈希表中
            HashMap<String, Integer> tmpMap = new HashMap<>();
            for (String s1 : subStr) {
                Integer value = tmpMap.getOrDefault(s1, 0);
                tmpMap.put(s1, value + 1);
            }
            //判断两个哈希表是否相等
            boolean flag = true;
            //先判断键是否相等,采用你中是否有我,我中是否有你的思路
            Set<String> keySet = map.keySet();
            Set<String> tmpSet = tmpMap.keySet();
            for (String key : keySet) {
                if (!tmpSet.contains(key)) {
                    flag = false;
                    break;
                }
            }
            if (!flag){
                continue;
            }
            for (String key : tmpSet) {
                if (!keySet.contains(key)) {
                    flag = false;
                    break;
                }
            }
            if (!flag){
                continue;
            }
            //再由键比较值
            for (String key : keySet) {
                int integer1 = map.get(key);
                int integer2 = tmpMap.get(key);
                if (integer1 != integer2) {
                    flag = false;
                }
            }
            if (!flag){
                continue;
            }
            //过关斩将法,如果前变条件都成立,则此子串满足,添加索引
            list.add(i);
        }
        return list;
    }
原文:https://www.cnblogs.com/mx-info/p/14790486.html