1. 题目

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).

2. 思路

没有特别的好方法,相当于死扛计算的。
注意:words里可能有重复。
注意:“ab”,“ba”, "aa", "bb"这种,彼此交叉的。

遍历起点,每次找到一个匹配点,然后验证是否符合需求。然后+1从下一个点开始找下一个起点。
起点当前的点的第一个串是其中一个。
验证方法是,看是否能匹配到words.size个。特殊处理words里重复的情况,通过计数处理。
为每一个起点开始的匹配,为word命名一个version,记录下version。重复出现version时进行count比较。count超了就失败。

3. 代码

耗时:849ms

class Solution {
public:
    vector<int> findSubstring(string& s, vector<string>& words) {
        //cout << "s=" << s << endl;
        vector<int> ret;
        if (words.size() == 0) {
            return ret;
        }
        unordered_map<string, int> map;
        unordered_map<string, int> freq;
        for (int i = 0; i < words.size(); i++) {
            map[words[i]] = 0;
            if (freq.find(words[i]) != freq.end()) {
                freq[words[i]]++;
            } else {
                freq[words[i]] = 1;
            }
        }
        int version = 0;
        
        size_t i = 0;
        size_t one_len = words[0].length();
        size_t num = words.size();
        size_t total_len = one_len * num;
        while (i < s.length() - total_len + 1) {
            i = findFirstOf(s, i, words);
            if (i == string::npos) {
                return ret;
            }
            string s1 = s.substr(i, one_len);
            version++;
            
            unordered_map<string, int> cnt;
            cnt[s1] = 1;
            
            //cout << "i=" << i << " version=" << version << " s1=" << s1 << endl;
            int count = 0;
            int k = i;
            map[s1] = version;
            //cout << "count=" << count << " k=" << k << " str=" << s1 << " it=" << version << endl;
            k += one_len;
            count++;
            while (count < num) {
                string s1 = s.substr(k, one_len);
                auto it = map.find(s1);
                //cout << "count=" << count << " k=" << k << " str=" << s1 << " it=" << (it == map.end() ? -1 : it->second) << endl;
                if (it == map.end()) {
                    break;
                }
                if (it->second == version) {
                    cnt[s1]++;
                    if (cnt[s1] > freq[s1]) {
                        break;
                    }
                } else {
                    cnt[s1] = 1;
                }
                map[s1] = version;
                k += one_len;
                count++;
            }
            if (count == num) {
                ret.push_back(i);
                //cout << "find idx: " << i << endl;
            }
            i++;
        }
        return ret;
    }
    
    size_t findFirstOf(string&s, size_t b, vector<string>& words) {
        size_t min = s.length();
        for (int i = 0; i < words.size(); i++) {
            size_t cur = s.find(words[i], b);
            //cout << "firstOf: " << words[i] << " cur=" << cur << " s=" << s.substr(b) << endl;
            if (cur == string::npos) {
                return string::npos;
            }
            if (cur < min) {
                min = cur;
            }
        }
        if (min == s.length()) {
            return string::npos;
        } else {
            return min;
        }
    }
};

knzeus
72 声望28 粉丝

行万里路,读万卷书