Skip to content
On this page

Number of Matching Subsequeces

leetcode 792. Number of Matching Subsequences

Approach 1: Brute Force

Intuition

loop through all possibilities.

Code

cpp
int numMatchingSubseq(string s, vector<string>& words) {
    unordered_map<char, deque<int>>mp;
    for(int i = 0; i < s.size(); i++)
        mp[s[i]].push_back(i);


    int res = 0, j, cnt;
    for(int i = 0; i < words.size(); i++) {
        vector<int>v(words[i].size()+1, -1);
        for(j = 0; j < words[i].size(); j++) {
            auto it = mp[words[i][j]];
            cnt = 0;
            if(it.size() == 0)
                break;
            while(it.size() > 0 && cnt < it.size() && it[cnt] <= v[j])
                cnt++;
            if(cnt >= it.size())
                break;
            v[j+1] = it[cnt];
        }
        if(j==words[i].size())res++;
    }

    return res;
}

Complextiy Analysis

Time: O(m*n)

Space: O(m+n)

Intuition

First, we store characters in string s in alpha with its indexes.

Then, simular to Approach 1, but we use binary search to identify if its a vaild word. For example, if int c = words[i][j] - 'a', but it appears that alpha[c].size() == 0 or last words' characters' indexes in s is larger than the largest element in alpha[c], then we can say this word is not vaild.

Code

cpp
int numMatchingSubseq(string s, vector<string>& words) {
    vector<vector<int>> alpha(26);

    for(int i = 0; i < s.size(); i++)
        alpha[s[i]-'a'].push_back(i);

    int res = 0;
    for(int i = 0; i < words.size(); i++) {
        int pivot = -1;
        bool found = true;

        for(int j = 0; j < words[i].size(); j++) {
            auto it = upper_bound(alpha[words[i][j]-'a'].begin(), alpha[words[i][j]-'a'].end(), pivot);
            if(it == end(alpha[words[i][j]-'a']))
                found = false;
            else
                pivot = *it;
        }

        if(found)
            res++;
    }

    return res;
}

Complextiy Analysis

Time: O(log(m)*n)

Space: O(m)

Approach 3: Trie

Intuition

First, we have a vector to store words base on its back() char.

Second, we loop through s form end to begin, check s[i] key in vector, and reallocate words stored in vector[s[i]] using first step, and repeat that.

Code

cpp
int numMatchingSubseq(string s, vector<string>& words) {
    vector<vector<string>> w(126);
    for(auto& i : words)
        w[i.back()].push_back(i);

    int res = 0;
    for(int i = s.size()-1; i >= 0; i--) {
        auto temp = w[s[i]];
        w[s[i]].clear();
        for(auto& j : temp) {
            j.pop_back();
            if(j.size() == 0) res++;
            else w[j.back()].push_back(j);
        }
    }
    return res;

}

Complextiy Analysis

Time: O(m*log(n))

Space: O(n)

Some Super Dope Code Exhibition

Approach 3

from @mzchen

cpp
int numMatchingSubseq(string S, vector<string>& words) {
    vector<string::iterator> waiting[128];
    for (auto &word : words)
        waiting[word[0]].emplace_back(word.begin());
    for (char c : S) {
        vector<string::iterator> advance;
        swap(advance, waiting[c]);
        for (auto in : advance)
            waiting[*++in].emplace_back(in);
    }
    return waiting[0].size();
}

Released under the MIT License.