30. Substring with Concatenation of All Words (Solution) Leetcode题解

题目:

给定一个字符串,和一组单词,找出所有满足下面要求的子字符串(substring)开头的下标(index):

这些子字符串必须由给定那组单词串接组成,且每个单词在该子字符串中出现且仅出现一次。

For example, given:

s: "barfoothefoobarman"

words: ["foo", "bar"]

You should return the indices: [0,9].

Order does not matter.

思路:

最简单的方法就是枚举(Brute force),但时间复杂度是O(len(s)xlen(words)xlen(words[0])),我觉得会超时,这里就不讲了。有兴趣的读者可以自己试试,没准不会超时呢,反正我没试过。下面讲一定不会超时的方法。

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        unordered_map<string, int> ref;
        vector<int> ans;
        for(auto s: words) ref[s] += 1;
        int l = words[0].size(), n = s.size(), m = words.size();
        for(int i=0; i<m*l; i++) {
            unordered_map<string, int> cnt;
            int j = i, k = i;
            while(k <= n - l) {
                string buf = s.substr(k, l);
                k += l;
                if(!ref.count(buf)) {
                    cnt.clear();
                    j = k;
                } else {
                    cnt[buf]++;
                    while(cnt[buf] > ref[buf]) {
                        string buf1 = s.substr(j, l);
                        cnt[buf1]--;
                        j += l;
                    }
                    if(k - j == m * l) {
                        ans.push_back(j);
                    }
                }
            }
        }
        return ans;
    }
};
  • Performance 还可以:
class Solution {
    const int K = 1000000007;
    const int p = 199;
    inline int add(const int& x, const int& y) {
        return (x + y) % K;
    }
    inline void add_to(int &x, const int& y) {
        x += y;
        if(x >= K) x -= K;
    }
    inline int multiply(const int& x, const int& y) {
        return int((long(x) * y) % K);
    }
    inline int minus(const int& x, const int& y) {
        return (long(x) + K - y) % K;
    }
    int pwr(int n) {
        int x = p, ans = 1;
        while(n) {
            if(n & 1) ans = multiply(ans, x);
            x = multiply(x, x);
            n >>= 1;
        }
        return ans;
    }

public:
    vector<int> findSubstring(string s, vector<string>& words) {
        int n = s.size(), m = words.size(), l = words[0].size();
        int factor = pwr(l);
        unordered_map<int, int> ref;
        for(auto str: words) {
            int tmp = 0;
            for(int j = l - 1; j >= 0; --j) {
                tmp = multiply(tmp, p);
                tmp += (int)str[j];
            }
            ref[tmp] += 1;
        }
        vector<int> hash(n + 1, 0), ans;
        for(int j = n - 1; j >= 0; --j) {
            hash[j] = multiply(hash[j + 1], p);
            hash[j] += (int)s[j];
        }
        for(int i = 0; i < n; i++) {
            unordered_map<int, int> cnt;
            int j = i, k = i;  
            while(j <= n - m * l && k <= n - l) {
                while(k <= n - l && ref.count(buf1)) break;
                if(!ref.count(buf1)) {
                    cnt.clear();
                    j = k = k + l;
                } else if(cnt[buf1] > ref[buf1]) {
                    while((buf2 = minus(hash[j], multiply(hash[j + l], factor))) != buf1) {
                        cnt[buf2]--;
                        j += l;
                    }
                    cnt[buf2]--;
                    j += l;
                } else {
                    ans.push_back(j);
                    cnt[minus(hash[j], multiply(hash[j + l], factor))]--;
                    j += l;
                }
            }
        }
        return ans;
    }
};