zoukankan      html  css  js  c++  java
  • 030串联所有单词并匹配

      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 }
  • 相关阅读:
    Node实践之二
    Node实践之一
    总结的JS数据类型判定(非常全面)
    利用chorme调试手机网页
    设计模式总结综述
    Python3标准库使用样例
    systemd 文档教程
    编写Postgres扩展之五:代码组织和版本控制
    编写Postgres扩展之三:调试
    编写Postgres扩展之四:测试
  • 原文地址:https://www.cnblogs.com/zzw1024/p/10537699.html
Copyright © 2011-2022 走看看