30. Substring with Concatenation of All Words (JAVA)

You are given a string, s, and a list of words, words, that are all of the same length. Find all starting indices of substring(s) in s that is a concatenation of each word in words exactly once and without any intervening characters.

Example 1:

Input:
  s = "barfoothefoobarman",
  words = ["foo","bar"]
Output: [0,9]
Explanation: Substrings starting at index 0 and 9 are "barfoor" and "foobar" respectively.
The output order does not matter, returning [9,0] is fine too.

Example 2:

Input:
  s = "wordgoodgoodgoodbestword",
  words = ["word","good","best","word"]
Output: []
 
class Solution {
    public List<Integer> findSubstring(String s, String[] words) {
        List<Integer> ret = new ArrayList<>(); 
        if(words==null || words.length==0) return ret;
        
        int start; //start index of s
        int cur; //current index of s
        Map<String, Integer> wordCnt= new HashMap<String, Integer>(); //count of each word
        Map<String, Integer> strCnt= new HashMap<String, Integer>(); //count of each word while traversing string
        String w;
        String w_to_del;
        int startIndex;
        int cnt;
        int len = words[0].length();
        int strLen = words.length * len;
        
        //initialize map
        for(String str: words){
            wordCnt.put(str,wordCnt.getOrDefault(str,0)+1);
        }
        
        for(int j = 0; j < len; j++){ //word可能会出现在s的任意位置,而非仅仅0,len,2*len...的位置
            startIndex = j;
            strCnt.clear();
            for(int i = j; i <= s.length()-len; i+=len){
                w = s.substring(i,i+len);
                if(wordCnt.containsKey(w)){ //word in words
                    strCnt.put(w, strCnt.getOrDefault(w,0)+1);
                    //number of word in string is more than that in words array, move right startIndex
                    while(strCnt.get(w) > wordCnt.get(w)){
                        w_to_del = s.substring(startIndex,startIndex+len);
                        strCnt.put(w_to_del,strCnt.get(w_to_del)-1);
                        startIndex += len;
                    }   

                    //find a match
                    if(i + len - startIndex == strLen){
                        ret.add(startIndex);

                        //start to find another match from startIndex+len
                        w_to_del = s.substring(startIndex,startIndex+len);
                        strCnt.put(w_to_del,strCnt.get(w_to_del)-1);
                        startIndex += len;
                    }

                }
                else{ //word not in words
                    startIndex = i+len;
                    strCnt.clear();
                }
            }
        }
        return ret;
    }
}

 时间复杂度:通过window的方式,在每个word的起始位置,只要遍历一遍s,就能完成查询。一共有size =words.length个起始位置,所以时间复杂度是O(n*size),其中n为s的长度,在s很长的时候,可以认为size是可忽略的常量,时间复杂度为O(n)。

原文地址:https://www.cnblogs.com/qionglouyuyu/p/10797372.html