30. Substring with Concatenation of All Words

題目

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.

For example, given:
s: "barfoothefoobarman"
words: ["foo", "bar"]

You should return the indices: [0,9].
(order does not matter).

分析

這道題真的惡心到我了。一個下午都沒寫出來。不過后來弄出來之后又覺得異常簡單。
思路:由words可知最終組成的子串的長度,枚舉子串的開頭,依次判斷是否符合規則即可。

實現一

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words){
        vector<int> ans;
        int wl=words[0].size(), sl=s.size(), n=words.size();
        unordered_map<string, int> dict;
        for(int i=0; i<n; i++)
            dict[words[i]]++;
        
        unordered_map<string, int> times;
        for(int left=0; left+wl*n<=sl; left++){
            //init
            bool valid = true;
            for(int i=left; i<left+wl*n; i+=wl){
                string str = s.substr(i, wl);
                if(!dict.count(str)){
                    times.clear();
                    valid = false;
                    break;
                }
                times[str]++;
            }
            if(!valid) continue;
            
            //valid?
            for(int i=0; i<n; i++){
                if(times.count(words[i])==0 || dict[words[i]]!=times[words[i]]){
                    valid=false;
                    break;
                }
            }
            if(valid){
                ans.push_back(left);
            }
            
            //next
            times.clear();
        }
        return ans;
    }
};

思考一

提交成功后發現所有選手的運行時間的分布有兩個明顯的駝峰,而我的方法在后一個駝峰。所以考慮還有更好的算法。原算法的復雜度為O(slwln)思考后發現如果假設s是由與words中字符串長度相等的子串組成的話,會簡單很多。那么可以根據words中字符串的長度wl來將答案分為wl類,這樣可以將復雜度降為O(sl/wlwln)=O(sl*n)。而在每一組中,以wl為間隔枚舉開頭,并且在計算下一組的狀態時,可以通過“掉前一組的頭,加上這一組的尾”來實現。

實現二

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        vector<int> ans;
        int wl=words[0].size(), sl=s.size(), n=words.size();
        unordered_map<string, int> dict;
        for(int i=0; i<n; i++)
            dict[words[i]]++;
        
        for(int group=0; group<wl; group++){
            unordered_map<string, int> times;
            for(int count=0, left=group; left+n*wl<=sl; left+=wl){
                for(int i=left+count*wl; count<n && i+wl<=sl; i+=wl){
                    string str = s.substr(i, wl);
                    times[str]++;
                    count++;
                }
                if(count<n)
                    return ans;
                
                bool valid=true; 
                for(int i=0; i<n; i++){
                    if(times.count(words[i])==0 || dict[words[i]]!=times[words[i]]) {
                        valid=false;
                        break;
                    }
                }
                if(valid){
                    ans.push_back(left);
                }
                string str=s.substr(left, wl);
                times[str]--;
                count--;
                
            }
        }
        return ans;
    }
};

思考二

果然改變算法之后進入了第一梯隊,開心。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容