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

歡迎訪問(wèn) 生活随笔!

生活随笔

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

编程问答

hash 值重复_“重复”相关的问题

發(fā)布時(shí)間:2024/9/30 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 hash 值重复_“重复”相关的问题 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

重復(fù)子串比較的核心是使用 Rabin-Karp (Rolling Hash)。

Rabin-Karp字符串編碼的本質(zhì)是對(duì)字符串進(jìn)行哈希,將字符串之間的比較轉(zhuǎn)化為編碼之間的比較

有N個(gè)不同的字符,可以將字符組成的串,映射成 N進(jìn)制表示的10進(jìn)制數(shù)。每一個(gè)數(shù)可以代表一種字符。 去頭加尾的哈希計(jì)算可以在

的時(shí)間內(nèi)完成

題目A(困難)

1044. 最長(zhǎng)重復(fù)子串
給出一個(gè)字符串 S,考慮其所有重復(fù)子串(S 的連續(xù)子串,出現(xiàn)兩次或多次,可能會(huì)有重疊)。
返回任何具有最長(zhǎng)可能長(zhǎng)度的重復(fù)子串。(如果 S 不含重復(fù)子串,那么答案為 ""。)示例 1:輸入:"banana" 輸出:"ana" 示例 2:輸入:"abcd" 輸出:""

二分查找 + Rabin-Karp 字符串編碼

  • 從 1 到 N 中選取子串的長(zhǎng)度 L
  • 檢查字符串中是否存在長(zhǎng)度為 L 的重復(fù)子串
  • 子任務(wù)一:二分查找

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

    子任務(wù)二:是否存在長(zhǎng)度為L(zhǎng)的重復(fù)子串(Rabin-Karp 字符串編)

    使用 Rabin-Karp 算法將字符串進(jìn)行編碼,這樣只要有兩個(gè)編碼相同,就說(shuō)明存在重復(fù)子串。

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

    哈希計(jì)算公式

    字符一共有26,a最小可以取26.

    檢查當(dāng)前處于滑動(dòng)窗口中的子串的編碼是否已經(jīng)出現(xiàn)過(guò)(用一個(gè)集合存儲(chǔ)已經(jīng)出現(xiàn)過(guò)的編碼)。若已經(jīng)出現(xiàn)過(guò),就說(shuō)明找到了長(zhǎng)度為 L 的重復(fù)子串;若沒(méi)有出現(xiàn)過(guò),就把當(dāng)前子串的編碼加入到集合中。

    注意事項(xiàng):取模

    最后一個(gè)需要解決的問(wèn)題是,在實(shí)際的編碼計(jì)算中,hash值、

    可能會(huì)非常大,在 C++ 和 Java 語(yǔ)言中,會(huì)導(dǎo)致整數(shù)的上溢出。所以,需要對(duì)編碼值進(jìn)行取模,將編碼控制在一定的范圍內(nèi),防止溢出,即h = h % modulus。h = (h * a - nums[start - 1] * aL % modulus + modulus) % modulus; h = (h + nums[start + L - 1]) % modulus;

    注意事項(xiàng)2:哈希沖突

    取模會(huì)導(dǎo)致哈希沖突,既是有可能兩個(gè)字符串是不同的,但是哈希值相同。后續(xù)的話學(xué)習(xí)一下hash沖突的解決方式。

    最終代碼

    public int search(int L, int n, int[] nums) {// roll hash的base值,26個(gè)字符,用26進(jìn)制玩。int a = 26;// 防止hash值溢出,使用的mod數(shù)long modulus = (long) Math.pow(10, 16);// 計(jì)算長(zhǎng)度為L(zhǎng)的第一個(gè)子串的 roll hash 值long h = 0;for (int i = 0; i < L; ++i)h = (h * a + nums[i]) % modulus;// 存儲(chǔ)已出現(xiàn)過(guò)的hash值HashSet<Long> seen = new HashSet<>();seen.add(h);// 第一位的26的L冪 取模 : aL % moduluslong aL = 1;for (int i = 1; i <= L; ++i)aL = (aL * a) % modulus;for (int start = 1; start < n - L + 1; ++start) {// compute rolling hash in O(1) timeh = (h * a - nums[start - 1] * aL % modulus + modulus) % modulus;h = (h + nums[start + L - 1]) % modulus;if (seen.contains(h)) return start;seen.add(h);}return -1;}public String longestDupSubstring(String S) {int n = S.length();// 將字符串映射成 hash值 (26進(jìn)制的數(shù)值)// 實(shí)現(xiàn)常數(shù)時(shí)間復(fù)雜度的滑動(dòng)窗口int[] nums = new int[n];for (int i = 0; i < n; ++i)nums[i] = (int) S.charAt(i) - (int) 'a';// 二分搜索, L = 要定位的重復(fù)字符串的長(zhǎng)度int minRepeat = 1, maxRepeat = n;int L;while (minRepeat != maxRepeat) {L = minRepeat + (maxRepeat - minRepeat) / 2;if (search(L, n, nums) != -1)minRepeat = L + 1;elsemaxRepeat = L;}int start = search(minRepeat - 1, n, nums);return start != -1 ? S.substring(start, start + minRepeat - 1) : "";}

    總結(jié)

    以上是生活随笔為你收集整理的hash 值重复_“重复”相关的问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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