30. 串联所有单词的子串 - LeetCode

30. 串联所有单词的子串

题目链接

直接枚举所有子串


class Solution {
    public List<Integer> findSubstring(String s, String[] words) {
        int sLen = s.length();
        int n = words.length;
        int wordLen = words[0].length();
        int sumLen = wordLen * n;
        Map<String, Integer> map = new HashMap<>();
        for(int i = 0; i < n; i++){
            if(!map.containsKey(words[i]))
                map.put(words[i], 1);
            else map.put(words[i], map.get(words[i]) + 1);
        }
        List<Integer> list = new ArrayList<>();
        for(int i = 0; i < sLen - sumLen + 1; i++){
            boolean flag = true;
            Map<String, Integer> mapTemp = new HashMap<>(map);
            for(int j = i; j <= i + (n - 1) * wordLen; j += wordLen){
                String str = s.substring(j, j + wordLen);
                if(!mapTemp.containsKey(str) || mapTemp.get(str) == 0){
                    flag = false;
                    break;
                } else mapTemp.put(str, mapTemp.get(str) - 1);
            }
            if(flag) list.add(i);
        }
        return list;
    }
}
  • 使用map记录每个单词的可用次数,枚举起始点,判断是否可行
  • 时间复杂度为O(n2logn)

双指针滑动窗口

class Solution {
    public List<Integer> findSubstring(String s, String[] words) {
        int sLen = s.length();
        int n = words.length;
        int wordLen = words[0].length();
        int sumLen = wordLen * n;
        Map<String, Integer> map = new HashMap<>();
        for(int i = 0; i < n; i++){
            if(!map.containsKey(words[i]))
                map.put(words[i], 1);
            else map.put(words[i], map.get(words[i]) + 1);
        }
        List<Integer> list = new ArrayList<>();
        for(int k = 0; k < wordLen; k++){
            Map<String, Integer> mapTemp = new HashMap<>(map);
            int i = 0;
            for(int j = 0; k + (j + 1) * wordLen - 1 < sLen ; j++){
                String strJ = s.substring(k + j * wordLen, k + (j + 1) * wordLen);
                if(!mapTemp.containsKey(strJ)){
                    while(i < j){
                        String strI = s.substring(k + i * wordLen, k + (i + 1) * wordLen);
                        mapTemp.put(strI, mapTemp.get(strI) + 1);
                        i++;
                    }
                    i++;
                } else if(mapTemp.get(strJ) == 0){
                    while(i < j){
                        String strI = s.substring(k + i * wordLen, k + (i + 1) * wordLen);
                        if(strI.equals(strJ)){
                            i++;
                            break;
                        }
                        mapTemp.put(strI, mapTemp.get(strI) + 1);
                        i++;
                    }
                } else{
                    mapTemp.put(strJ, mapTemp.get(strJ) - 1);
                    if(j - i + 1 == n){
                        list.add(k + i * wordLen);
                        String strI = s.substring(k + i * wordLen, k + (i + 1) * wordLen);
                        mapTemp.put(strI, mapTemp.get(strI) + 1);
                        i++;
                    }
                }
            }
        }
        return list;
    }
}
  • 双指针分别表示当前子串的头尾,按顺序枚举尾指针,分为以下三种情况:

    • 若尾指针所在子串不在单词中,将头指针移过来,清空当前子串
    • 若尾指针所在子串的单词次数用完,则将头指针右移,直到该单词有可用次数
    • 若尾指针所在子串的单词有可用次数少,就用掉一次
      • 若此时所有单词都匹配,则加入list
  • 注意:因为每次都是按单词长度移动窗口,所以需要考虑起始点的offset

  • 时间复杂度为O(nlogn)

posted @ 2021-02-13 11:34  一天到晚睡觉的鱼  阅读(109)  评论(0)    收藏  举报