LeetCode 792. Number of Matching Subsequences / 1055. Shortest Way to Form String
792. Number of Matching Subsequences
Inverted Index + Binary Search
Brute Force 会 TLE,时间复杂度为 O(S*n + Σwords[i])。
可以对S中每个字符建立一个vector,保存其下标位置。这样就可以通过二分快速找到当前位置之后第一次出现的特定字符的下标。时间复杂度 O(S + Σ (words[i]*log(S)) )。
class Solution { public: int numMatchingSubseq(string S, vector<string>& words) { vector<vector<int>> pos(128); // pos[ch] is vector of indexes of ch in S for (int i=0;i<S.size();++i) pos[S[i]].push_back(i); int count=0; for (string word:words){ int prev=-1; for (char ch:word){ auto &index_vec=pos[ch]; auto it=upper_bound(index_vec.begin(),index_vec.end(),prev); if (it==index_vec.end()) goto outer; prev = *it; } ++count; outer:; } return count; } };
Inverted Index + Table
如果要更快,可以建立一个表 table[i][ch],记录S的第i个位置后,第一次出现ch的下标。表的构建可以从后往前扫描S,线性时间得到。时间复杂度 O(S + Σwords[i]),牺牲空间换时间。
class Solution { public: int numMatchingSubseq(string S, vector<string>& words) { // after_pos[i][ch] - the index of first ch after ith position of S vector<vector<int>> after_pos(S.size(),vector<int>(26,-1)); vector<int> first_pos(26,-1); // first_pos[ch] - the index of first ch in S for (int i=S.size()-1;i>=0;--i){ char ch=S[i]; for (int j=0;j<26;++j) after_pos[i][j] = first_pos[j]; first_pos[ch-'a'] = i; } int count=0; for (string word:words){ int i=0; int pos=first_pos[word[i++]-'a']; if (pos==-1) goto outer; while (i<word.size()){ pos = after_pos[pos][word[i++]-'a']; if (pos==-1) goto outer; } ++count; outer:; } return count; } };
Solution 的方法很像 Trie Tree,对所有word一起处理。时间复杂度也是 O(S + Σwords[i])。
https://leetcode.com/problems/number-of-matching-subsequences/solution/
1055. Shortest Way to Form String
和上一题一模一样,同样可以二分或者直接建表做。
class Solution { public: int shortestWay(string source, string target) { vector<vector<int>> pos(26); // pos[ch] - vector of indexes for (int i=0;i<source.size();++i) pos[source[i]-'a'].push_back(i); int count=0; int i=0, prev=-1; while (i<target.size()){ char ch=target[i]; auto &index_vec=pos[ch-'a']; if (index_vec.size()==0) return -1; auto it=upper_bound(index_vec.begin(),index_vec.end(),prev); if (it==index_vec.end()){ prev = -1; ++count; }else{ prev = *it; ++i; } } ++count; return count; } };