30. Substring with Concatenation

2017-09-29  本文已影响0人  Al73r

题目

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;
    }
};

思考二

果然改变算法之后进入了第一梯队,开心。

上一篇 下一篇

猜你喜欢

热点阅读