題意:
給出一個字符串 S,考慮其所有重復子串(S 的連續子串,出現兩次或多次,可能會有重疊)。
返回任何具有最長可能長度的重復子串。(如果 S 不含重復子串,那么答案為 ""。)
示例 1:
輸入:"banana"
輸出:"ana"
示例 2:
輸入:"abcd"
輸出:""
思路:(字符串hash+二分)
針對長度簡單的從length(S)-1遞減時間過長的問題。如果有長度為L的最長重復子串,則必然有L_0<L的重復子串,因此先采用二分法尋找到最長重復子串的長度。
51nod2619也利用了字符串hash

1 typedef unsigned long long ull; 2 const int N=1e5+10; 3 const ull base=23333; 4 class Solution { 5 public: 6 ull _hash[N],p[N]; 7 ull get(int l,int r){ 8 return _hash[r]-_hash[l-1]*p[r-l+1]; 9 } 10 void init(string s){ 11 p[0]=1; 12 for(int i=1;i<=s.size();i++){ 13 p[i]=p[i-1]*base; 14 _hash[i]=_hash[i-1]*base+s[i-1]-'a'; 15 } 16 } 17 int check(int mid,int len){ 18 unordered_map<ull,bool>mp; 19 for(int i=1;i+mid-1<=len;i++){ 20 ull k=get(i,i+mid-1); 21 if(mp.find(k)!=mp.end())return i; 22 mp[k]=true; 23 } 24 return 0; 25 } 26 string longestDupSubstring(string S) { 27 init(S); 28 int len=S.size(); 29 string ans=""; 30 int l=1,r=len-1; 31 while(l<=r){ 32 int mid=(l+r)/2; 33 if(check(mid,len))l=mid+1; 34 else r=mid-1; 35 } 36 l--; 37 if(l==-1)return ""; 38 int k=check(l,len); 39 return S.substr(k-1,l); 40 } 41 };