1044. 最长重复子串

1044. 最长重复子串 - 力扣(LeetCode) (leetcode-cn.com)

暴力失败 滑动窗口失败

  1 class Solution {
  2 public:
  3     // 暴力
  4     // string longestDupSubstring(string s) {
  5     //     string ans;
  6     //     vector<string> anss;
  7     //     for(int i = 0; i<s.size(); i++){
  8     //         for(int j = i+1; j<s.size(); j++){
  9     //             string tmp = s.substr(i, j-i);
 10     //             if(s.find(tmp)!=s.rfind(tmp) && s.rfind(tmp)!=-1){
 11     //                 anss.push_back(tmp);
 12     //                 cout<<tmp<<endl;
 13     //             }
 14     //         }
 15     //     }
 16     //     sort(anss.begin(), anss.end(), [](string a, string b)->bool{return a.size()>b.size();});
 17     //     return anss.size() == 0?"":anss[0];
 18     // }
 19 
 20     // 小优化
 21     // string longestDupSubstring(string s) {
 22     //     string ans;
 23     //     vector<string> anss;
 24     //     int bigger_size = 0;
 25     //     for(int i = 0; i<s.size(); i++){
 26     //         for(int j = i+1; j<s.size(); j++){
 27     //             string tmp = s.substr(i, j-i);
 28     //             if(s.find(tmp)!=s.rfind(tmp) && s.rfind(tmp)!=-1){
 29     //                 anss.push_back(tmp);
 30     //                 bigger_size = bigger_size>tmp.size()?bigger_size:tmp.size();
 31     //             }else break;
 32     //         }
 33     //     }
 34     //     sort(anss.begin(), anss.end(), [](string a, string b)->bool{return a.size()>b.size();});
 35     //     return anss.size() == 0?"":anss[0];
 36     // }
 37 
 38     // 滑动窗口 仍然超时
 39     // string longestDupSubstring(string s) {
 40     //     string ans;
 41     //     int bigger_size = 0;
 42     //     int i = 0, j = 1;
 43     //     while(i<s.size() && j<s.size()){
 44     //         string tmp = s.substr(i, j-i);  
 45     //         if(s.find(tmp)!=s.rfind(tmp) && s.rfind(tmp)!=-1 && tmp.size()>bigger_size){
 46     //             bigger_size = tmp.size();
 47     //             ans = tmp;
 48     //         }
 49     //         else
 50     //             i++;
 51     //         j++;  
 52     //     }
 53     //     return ans;
 54     // }
 55
 1     // 滑动窗口 优化 单个不超时 提交超时
 2     // string longestDupSubstring(string s) {
 3     //     string ans;
 4     //     int bigger_size = 0;
 5     //     int i = 0, j = 1;
 6     //     while(i<s.size() && j<s.size()){
 7     //         string tmp = s.substr(i, j-i);
 8     //         if(s.find(tmp)!=s.rfind(tmp) && s.rfind(tmp)!=-1 && tmp.size()>bigger_size){
 9     //             bigger_size = tmp.size();
10     //             j = i+bigger_size;
11     //             ans = tmp;
12     //         }
13     //         else
14     //             i++;
15     //         j++;
16     //     }
17     //     return ans;
18     // }
 56     // 从大到小
 57     // string longestDupSubstring(string s) {
 58     //     string ans;
 59     //     int findsize = s.size()-1;
 60     //     bool find = 0;
 61     //     while(findsize>0){
 62     //         for(int i = 0; i<s.size(); i++){
 63     //             if(i+findsize>s.size()-1) break;
 64     //             string tmp = s.substr(i, findsize);
 65     //             cout<< tmp<<endl;
 66     //             if(s.find(tmp)!=s.rfind(tmp) && s.rfind(tmp)!=-1){
 67     //                 ans = tmp;
 68     //                 find = 1;
 69     //                 break;
 70     //             }
 71     //         }
 72     //         if(find == 1) break;
 73     //         findsize--;
 74     //     }
 75     //     return ans;
 76     // }
 77 
 78     typedef pair<long long, long long> pll;
 79     long long pow(int a, int m, int mod) {
 80         long long ans = 1;
 81         long long contribute = a;
 82         while (m > 0) {
 83             if (m % 2 == 1) {
 84                 ans = ans * contribute % mod;
 85                 if (ans < 0) {
 86                     ans += mod;
 87                 }
 88             }
 89             contribute = contribute * contribute % mod;
 90             if (contribute < 0) {
 91                 contribute += mod;
 92             }
 93             m /= 2;
 94         }
 95         return ans;
 96     }
 97 
 98     int check(const vector<int> & arr, int m, int a1, int a2, int mod1, int mod2) {
 99         int n = arr.size();
100         long long aL1 = pow(a1, m, mod1);
101         long long aL2 = pow(a2, m, mod2);
102         long long h1 = 0, h2 = 0;
103         for (int i = 0; i < m; ++i) {
104             h1 = (h1 * a1 % mod1 + arr[i]) % mod1;
105             h2 = (h2 * a2 % mod2 + arr[i]) % mod2;
106             if (h1 < 0) {
107                 h1 += mod1;
108             }
109             if (h2 < 0) {
110                 h2 += mod2;
111             }
112         }
113         // 存储一个编码组合是否出现过
114         set<pll> seen;
115         seen.emplace(h1, h2);
116         for (int start = 1; start <= n - m; ++start) {
117             h1 = (h1 * a1 % mod1 - arr[start - 1] * aL1 % mod1 + arr[start + m - 1]) % mod1;
118             h2 = (h2 * a2 % mod2 - arr[start - 1] * aL2 % mod2 + arr[start + m - 1]) % mod2;
119             if (h1 < 0) {
120                 h1 += mod1;
121             }
122             if (h2 < 0) {
123                 h2 += mod2;
124             }
125 
126             // 如果重复,则返回重复串的起点
127             if (seen.count(make_pair(h1, h2))) {
128                 return start;
129             }
130             seen.emplace(h1, h2);
131         }
132         // 没有重复,则返回-1
133         return -1;
134     }
135 
136     string longestDupSubstring(string s) {
137         srand((unsigned)time(NULL));
138         // 生成两个进制
139         int a1 = random()%75 + 26;
140         int a2 = random()%75 + 26;
141 
142         // 生成两个模
143         int mod1 = random()%(INT_MAX - 1000000006) + 1000000006;
144         int mod2 = random()%(INT_MAX - 1000000006) + 1000000006;
145         int n = s.size();
146         // 先对所有字符进行编码
147         vector<int> arr(n);
148         for (int i = 0; i < n; ++i) {
149             arr[i] = s[i] - 'a';
150         }
151         // 二分查找的范围是[1, n-1]
152         int l = 1, r = n - 1;
153         int length = 0, start = -1;
154         while (l <= r) {
155             int m = l + (r - l + 1) / 2;
156             int idx = check(arr, m, a1, a2, mod1, mod2);
157             if (idx != -1) {
158                 // 有重复子串,移动左边界
159                 l = m + 1;
160                 length = m;
161                 start = idx;
162             } else {
163                 // 无重复子串,移动右边界
164                 r = m - 1;
165             }
166         }
167         return start != -1 ? s.substr(start, length) : "";
168     }
169 };
原文地址:https://www.cnblogs.com/qianxunslimg/p/15725752.html