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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

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

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

目錄

最長(zhǎng)重復(fù)子串

C++代碼


最長(zhǎng)重復(fù)子串

1044. 最長(zhǎng)重復(fù)子串

給出一個(gè)字符串?S,考慮其所有重復(fù)子串(S?的連續(xù)子串,出現(xiàn)兩次或多次,可能會(huì)有重疊)。

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

示例 1:

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

示例 2:

輸入:"abcd" 輸出:""

提示:

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

    我們可以把這個(gè)問題分解成兩個(gè)子問題:

    從 1 到 N 中選取子串的長(zhǎng)度 L;

    檢查字符串中是否存在長(zhǎng)度為 L 的重復(fù)子串。

    子任務(wù)一:二分查找

    解決子問題一的最簡(jiǎn)單的方法是,我們從 L = N - 1 開始,依次遞減選取子串的長(zhǎng)度,并進(jìn)行判斷。如果發(fā)現(xiàn)存在長(zhǎng)度為 L 的重復(fù)子串,就表示 L 是最長(zhǎng)的可能長(zhǎng)度。

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

    子任務(wù)二:Rabin-Karp 字符串編碼

    我們可以使用 Rabin-Karp 算法將字符串進(jìn)行編碼,這樣只要有兩個(gè)編碼相同,就說明存在重復(fù)子串。對(duì)于選取的長(zhǎng)度 L:

    使用長(zhǎng)度為 L 的滑動(dòng)窗口在長(zhǎng)度為 N 的字符串上從左向右滑動(dòng);

    檢查當(dāng)前處于滑動(dòng)窗口中的子串的編碼是否已經(jīng)出現(xiàn)過(用一個(gè)集合存儲(chǔ)已經(jīng)出現(xiàn)過的編碼);

    若已經(jīng)出現(xiàn)過,就說明找到了長(zhǎng)度為 L 的重復(fù)子串;

    若沒有出現(xiàn)過,就把當(dāng)前子串的編碼加入到集合中。

    C++代碼

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

    總結(jié)

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

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。