1 #include "000库函数.h" 2 3 //自解; 4 //这道题 的突破口就是找到words的组合情况 5 //然后将所有组合一一查找是否存在子串,还要对答案去重、查找相同子串不同位置出现!!! 6 //超出时间限制^_^,悲催,做了一个小时 7 class Solution { 8 public: 9 vector<int> findSubstring(string s, vector<string>& words) { 10 set<int> R;//可以对答案进行去重! 11 vector<int>Res; 12 vector<string>v; 13 if (s.size() == 0)return Res; 14 Permutation(v, words, 0, words.size() - 1); 15 for (int i = 0; i < v.size(); ++i) { 16 string sub; 17 sub = v[i]; 18 int a = s.find(sub); 19 while (a >= 0) { 20 R.insert(a); 21 if(a+1<s.size()) 22 a = s.find(sub,a+1);//向后查找!! 23 } 24 } 25 Res.assign(R.begin(), R.end()); 26 return Res; 27 28 } 29 30 31 void swap(vector<string>& words, int k, int i) { 32 string s; 33 s = words[k]; 34 words[k] = words[i]; 35 words[i] = s; 36 } 37 38 void Permutation(vector<string>&v, vector<string>&words,int k, int m)//使用递归对words进行全排列 39 { 40 if (k == m) 41 { 42 static int num = 1; //局部静态变量,用来统计全排列的个数 43 string s = ""; 44 for (int i = 0; i < words.size(); ++i) 45 s += words[i]; 46 v.push_back(s); 47 cout << "第" << num++ << "个排列为: " << v[v.size() - 1] << endl; 48 } 49 else 50 { 51 for (int i = k; i <= m; i++) 52 { 53 swap(words, k,i); 54 Permutation(v,words,k+1, m); 55 swap(words, k, i); 56 } 57 } 58 } 59 60 61 }; 62 63 //博客答案 64 //这道题我们需要用到两个哈希表,第一个哈希表先把所有的单词存进去, 65 //然后从开头开始一个个遍历,停止条件为当剩余字符个数小于单词集里所有字符的长度。 66 //这时候我们需要定义第二个哈希表,然后每次找出给定单词长度的子串,看其是否在第一个哈希表里, 67 //如果没有,则break,如果有,则加入第二个哈希表,但相同的词只能出现一次,如果多了,也break。 68 //如果正好匹配完给定单词集里所有的单词,则把i存入结果中,具体参见代码如下: 69 //400ms 70 71 class Solution { 72 public: 73 vector<int> findSubstring(string s, vector<string>& words) { 74 vector<int> res; 75 if (s.empty() || words.empty()) return res; 76 int n = words.size(), m = words[0].size(); 77 unordered_map<string, int> m1; 78 for (auto &a : words) ++m1[a];//将单词存入哈希表中 79 for (int i = 0; i <= (int)s.size() - n * m; ++i) {//大大减少了循环次数 80 unordered_map<string, int> m2; 81 int j = 0; 82 for (j = 0; j < n; ++j) { 83 string t = s.substr(i + j * m, m);//从s的0位开始向后截取一个单词长度的子串 84 if (m1.find(t) == m1.end()) break;//未找到 85 ++m2[t];// 86 if (m2[t] > m1[t]) break; 87 } 88 if (j == n) res.push_back(i); 89 } 90 return res; 91 } 92 }; 93 94 //这道题还有一种O(n)时间复杂度的解法,设计思路非常巧妙,但是感觉很难想出来,博主目测还未到达这种水平。 95 //这种方法不再是一个字符一个字符的遍历,而是一个词一个词的遍历,比如根据题目中的例子,字符串s的长度n为18, 96 //words数组中有两个单词(cnt = 2),每个单词的长度len均为3,那么遍历的顺序为0,3,6,8,12,15, 97 //然后偏移一个字符1,4,7,9,13,16,然后再偏移一个字符2,5,8,10,14,17,这样就可以把所有情况都遍历到, 98 //我们还是先用一个哈希表m1来记录words里的所有词,然后我们从0开始遍历,用left来记录左边界的位置, 99 //count表示当前已经匹配的单词的个数。然后我们一个单词一个单词的遍历,如果当前遍历的到的单词t在m1中存在, 100 //那么我们将其加入另一个哈希表m2中,如果在m2中个数小于等于m1中的个数,那么我们count自增1,如果大于了, 101 //那么需要做一些处理,比如下面这种情况, s = barfoofoo, words = { bar, foo, abc }, 我们给words中新加了一个abc, 102 //目的是为了遍历到barfoo不会停止,那么当遍历到第二foo的时候, m2[foo] = 2, 而此时m1[foo] = 1,这是后已经不连续了, 103 //所以我们要移动左边界left的位置,我们先把第一个词t1 = bar取出来,然后将m2[t1]自减1,如果此时m2[t1] < m1[t1]了, 104 //说明一个匹配没了,那么对应的count也要自减1,然后左边界加上个len,这样就可以了。如果某个时刻count和cnt相等了, 105 //说明我们成功匹配了一个位置,那么将当前左边界left存入结果res中,此时去掉最左边的一个词,同时count自减1, 106 //左边界右移len,继续匹配。如果我们匹配到一个不在m1中的词,那么说明跟前面已经断开了,我们重置m2,count为0, 107 //左边界left移到j + len,参见代码如下: 108 109 110 //此解法牛逼,80ms 111 112 class Solution { 113 public: 114 vector<int> findSubstring(string s, vector<string>& words) { 115 if (s.empty() || words.empty()) return {}; 116 vector<int> res; 117 int n = s.size(), cnt = words.size(), len = words[0].size(); 118 unordered_map<string, int> m1; 119 for (string w : words) ++m1[w]; 120 for (int i = 0; i < len; ++i) {//总共一个单词的长度 121 int left = i, count = 0;//count 122 unordered_map<string, int> m2; 123 for (int j = i; j <= n - len; j += len) {//分为n/len个点位进行比较 124 string t = s.substr(j, len); 125 if (m1.count(t)) { 126 ++m2[t]; 127 if (m2[t] <= m1[t]) { 128 ++count; 129 } 130 else { 131 while (m2[t] > m1[t]) { 132 string t1 = s.substr(left, len); 133 --m2[t1]; 134 if (m2[t1] < m1[t1]) --count; 135 left += len; 136 } 137 } 138 if (count == cnt) {//计数等于单词个数,说明匹配成功 139 res.push_back(left); 140 --m2[s.substr(left, len)]; 141 --count; 142 left += len; 143 } 144 } 145 else { 146 m2.clear(); 147 count = 0; 148 left = j + len; 149 } 150 } 151 } 152 return res; 153 } 154 }; 155 156 void T030() { 157 string s = "foobarfoobar"; 158 vector<string> words = { "foo", "bar" }; 159 vector<int>Res; 160 Solution sol; 161 Res = sol.findSubstring(s, words); 162 for (auto i : Res) 163 cout << i << endl; 164 165 }