You are given a string, S, and a list of words, L, that are all of the same length. Find all starting indices of substring(s) in S that is a concatenation of each word in L exactly once and without any intervening characters.
For example, given:
S:
L:
You should return the indices:
(order does not matter).
Analysis:For example, given:
S:
"barfoothefoobarman"
L:
["foo", "bar"]
You should return the indices:
[0,9]
.(order does not matter).
The first solution I tried is to build a hash map that has all the combinations of words, so that we could have O(n/k) processing time afterwards, where n is the length of string S, and k is the length of a concatenated string. But I got MLE...
The second algorithm - see Sol 2 - , which is straightforward, got me an AC. Basically, we traverse the entire string S and check one word (NOT the concatenated long string!) at a time:
- if it matches our hash map, we check next word and so on;
- otherwise, we break immediately to check the word starts at next index
In the worst situation, where every time we check till the last word, we have O(n*m) time complexity, where n is the length of string S and m is the number of words in L.
Code:
Sol 1 - Memory Limit Exceed
class Solution { public: vector<int> findSubstring(string S, vector<string> &L) { unordered_set<string> comb; // store all combinations of L vector<int> res; string src=""; for (int i=0; i<L.size(); i++) { src+=L[i]; } // build up all permutations int match_len=L.size()*L[0].size(); permute(comb, src, 0, match_len); // scan S for (int i=0; i<S.length(); i++) { if (i+match_len<S.length()) { string match_str=S.substr(i, match_len); if (comb.find(match_str)!=comb.end()) res.push_back(i); } } return res; } void permute(unordered_set<string> &comb, string &src, int st, int len) { if (st>=len-1) { comb.emplace(src); return; } for (int i=st; i<len; i+=3) { swap_words(src, st, i); permute(comb, src, st+3, len); swap_words(src, st, i); } } void swap_words(string &src, int a, int b) { string tmp_a=src.substr(a,3); string tmp_b=src.substr(b,3); for (int i=a; i<a+3; i++) src[i]=tmp_b[i-a]; for (int i=b; i<b+3; i++) src[i]=tmp_a[i-b]; } };
Sol 2 - AC
class Solution { public: vector<int> findSubstring(string S, vector<string> &L) { vector<int> res; unordered_map<string,int> map; for (int i=0; i<L.size(); i++) map[L[i]]++; // scan S int len=L[0].size(); int match_len=L.size()*len; if (S.size()<match_len) return res; for (int i=0; i<=S.size()-match_len; i++) { unordered_map<string, int> map2; int j=0; for (j=0; j<match_len; j+=len) { string sub=S.substr(i+j, len); if (map.find(sub)!=map.end()) { map2[sub]++; if (map2[sub]>map[sub]) break; } else // immediately end loop break; } // check if two map are the same if (j==match_len) res.push_back(i); } return res; } };
No comments:
Post a Comment