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 };