日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

最长重复子串(Rabin-Karp算法)

發布時間:2025/3/15 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 最长重复子串(Rabin-Karp算法) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

最長重復子串

C++代碼


最長重復子串

1044. 最長重復子串

給出一個字符串?S,考慮其所有重復子串(S?的連續子串,出現兩次或多次,可能會有重疊)。

返回任何具有最長可能長度的重復子串。(如果?S?不含重復子串,那么答案為?""。)

示例 1:

輸入:"banana" 輸出:"ana"

示例 2:

輸入:"abcd" 輸出:""

提示:

  • 2 <= S.length <= 10^5
  • S?由小寫英文字母組成。
  • 方法一:二分查找 + Rabin-Karp 字符串編碼
    分析

    我們可以把這個問題分解成兩個子問題:

    從 1 到 N 中選取子串的長度 L;

    檢查字符串中是否存在長度為 L 的重復子串。

    子任務一:二分查找

    解決子問題一的最簡單的方法是,我們從 L = N - 1 開始,依次遞減選取子串的長度,并進行判斷。如果發現存在長度為 L 的重復子串,就表示 L 是最長的可能長度。

    但我們發現,如果字符串中存在長度為 L 的重復子串,那么一定存在長度為 L0 < L 的重復子串(選取長度為 L 的重復子串的某個長度為 L0 的子串即可),因此我們可以使用二分查找的方法,找到最大的 L。

    子任務二:Rabin-Karp 字符串編碼

    我們可以使用 Rabin-Karp 算法將字符串進行編碼,這樣只要有兩個編碼相同,就說明存在重復子串。對于選取的長度 L:

    使用長度為 L 的滑動窗口在長度為 N 的字符串上從左向右滑動;

    檢查當前處于滑動窗口中的子串的編碼是否已經出現過(用一個集合存儲已經出現過的編碼);

    若已經出現過,就說明找到了長度為 L 的重復子串;

    若沒有出現過,就把當前子串的編碼加入到集合中。

    C++代碼

    class Solution { public: //檢查是針對存在重復子串 還是發生了哈希沖突bool check_hash(string& s, pair<int, int>& a, pair<int, int> b) { //查看是否是真重復子串還是因為發生哈希碰撞而導致哈希值相同for (int i = a.first, j = b.first; i != a.second && j != b.second; ++i, ++j) {if (s[i] != s[j]) return false;}return true;}//檢查字符串s中是否存在長度為len的重復子串,如果有則返回該子串,否則返回空字符串string check(string& s, int len){int base = 26;//二十六個字母對應二十六進制int mod = 1000007;//取模 避免哈希沖突int num = 0;for(int i = 0; i < len; i++)//計算出第一個len長度的哈希映射值num = (num * base + s[i] - 'a')%mod;unordered_map<int, pair<int, int>> seen;//存儲的是哈希映射值及對應的坐標seen.insert({num, {0, len - 1}});int al = 1;//根據公式 計算出常數a的len次方for(int i = 1; i <= len; i++)al = (al * base)%mod;//遍歷字符串 計算每一個長度為len的子串的哈希映射值for(int i = 1; i < s.size() - len + 1; i++){//計算長度為len的子串的哈希映射值num = num * base - ((s[i-1] - 'a') * al)%mod;while(num < 0) num += mod;num = (num + (s[i + len - 1] - 'a'))%mod;//查找是否有重復的子串if(seen.count(num))if(check_hash(s, seen[num], {i, i + len - 1}))return s.substr(i, len);//如果是真的存在而不是因為哈希沖突,就返回這個子串seen.insert({num, {i, i + len - 1}});//如果是哈希沖突 就插入}return "";}//返回字符串s最長重復子串string longestDupSubstring(string s) {int m = s.size();int left = 0, right = m;string res = "";while(left < right){int mid = left + (right - left)/2;//二分法找到最長重復子串string tmp = check(s, mid);if(!tmp.empty()){//如果存在重復子串,就保存下來最長的一個重復子串res = tmp.size() > res.size() ? tmp : res;left = mid + 1;}elseright = mid;}return res;} };

    總結

    以上是生活随笔為你收集整理的最长重复子串(Rabin-Karp算法)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。