字串處理 Rabin-Karp (Rolling Hash)及相關LeetCode題目
關於我的 Leetcode 題目解答,程式碼前往 Github:https://github.com/chenxiangcyr/leetcode-answers
LeetCode題目:686 Repeated String Match
Given two strings A and B, find the minimum number of times A has to be repeated such that B is a substring of it. If no such solution, return -1.
For example, with A = "abcd" and B = "cdabcdab".
Return 3, because by repeating A three times (“abcdabcdabcd”), B is a substring of it; and B is not a substring of A repeated two times ("abcdabcd").
傳統演算法程式碼如下:時間複雜度O(length(A) * length(B))
class Solution {
public int repeatedStringMatch(String A, String B) {
for(int i = 0; i < A.length(); i++) {
// find the first match index
if(A.charAt(i) == B.charAt(0)) {
int times = 1;
int k = i;
int j = 0;
while(j < B.length() && A.charAt(k) == B.charAt(j)) {
j++;
// reach the end of A and not reach the end of B, times + 1
if(k == A.length() - 1 && j < B.length()) {
k = 0;
times++;
}
else {
k++;
}
}
// reach the end of B
if(j == B.length()) {
return times;
}
}
}
return -1;
}
}
Rabin-Karp (Rolling Hash 旋轉雜湊)演算法
字串可以理解為字元陣列,而字元可以被轉換為整數,可以把字串當成一個整形陣列。
找到一種方式將一組整形數字轉化為一個數字,就能夠使得我們藉助一個預期的輸入值來Hash字串。
假設,一個模式串 P
(需要被匹配的串)長度為L
,需要在其中查詢匹配的串S
長度為N
。
一種在S
中查詢P
的方式為:
- 雜湊
P
得到h(P)
,時間複雜度O(L)
- 從
S
的索引為0開始來列舉S
里長度為L
的子串,雜湊子串並計算出h(P)'
,時間複雜度O(N*L)
。 - 如果一個子串的雜湊值
h(P)'
與h(P)
匹配,將該子串與P
進行比較,時間複雜度O(L)
這個做法的時間複雜度為 O(N*L)
。我們可以通過使用 Rolling Hash 來優化這種做法。在上述步驟2中,我們看到對於 O(N)
的子串,都花費了 O(L)
來雜湊他們,然而可以看到這些子串中很多字元都是重複的。
我們可以利用前一個子串的計算結果雜湊值來計算當前子串的雜湊值。因此在上述步驟2中,時間複雜度可以優化為O(N)
假設第一個子串雜湊值H0 = (S[0] * 10^2 + S[1] * 10^1 + S[2] * 10^0) mod m
則第二個子串雜湊值H1 = (10 * H0 - S[0] * 10^3 + S[3] * 10^0) mod m
程式碼如下:時間複雜度O(length(A) + length(B))
class Solution {
public boolean check(int index, String A, String B) {
for (int i = 0; i < B.length(); i++) {
if (A.charAt((i + index) % A.length()) != B.charAt(i)) {
return false;
}
}
return true;
}
public int repeatedStringMatch(String A, String B) {
int q = (B.length() - 1) / A.length() + 1;
// 素數
int p = 113;
int MOD = 1_000_000_007;
// 乘法逆模
int pInv = BigInteger.valueOf(p).modInverse(BigInteger.valueOf(MOD)).intValue();
// 計算字串B的雜湊值,時間複雜度 O(B.length())
long bHash = 0, power = 1;
for (int i = 0; i < B.length(); i++) {
bHash += power * B.codePointAt(i);
bHash %= MOD;
power = (power * p) % MOD;
}
// 計算字串A的第一個子串雜湊值,時間複雜度 O(B.length())
long aHash = 0; power = 1;
for (int i = 0; i < B.length(); i++) {
aHash += power * A.codePointAt(i % A.length());
aHash %= MOD;
power = (power * p) % MOD;
}
// 如果一個子串的雜湊值與 B 的雜湊值匹配,將該子串與 B 進行比較,時間複雜度 O(B.length())
if (aHash == bHash && check(0, A, B)) return q;
power = (power * pInv) % MOD;
// 利用前一個子串的計算結果雜湊值來計算當前子串的雜湊值
for (int i = B.length(); i < (q + 1) * A.length(); i++) {
aHash -= A.codePointAt((i - B.length()) % A.length());
aHash *= pInv;
aHash += power * A.codePointAt(i % A.length());
aHash %= MOD;
if (aHash == bHash && check(i - B.length() + 1, A, B)) {
return i < q * A.length() ? q : q + 1;
}
}
return -1;
}
}
相關文章
- 字串相關題幹:字串
- 專案常用JS方法封裝(三) [ 字串相關處理 ]JS封裝字串
- 醫學影像處理相關軟體及python包Python
- 影象識別及處理相關資料集介紹
- opencv 視訊處理相關OpenCV
- Linux下處理時間同步相關問題彙總Linux
- 創新實訓(八)——題目相關的邏輯處理解釋
- webpack基礎–css相關處理WebCSS
- 字串處理字串
- MVC字串處理及MVC@RenderSection小計MVC字串
- 數字影像處理相關練習
- 處理若干行輸出的題目
- 處理一串字串的關鍵字字串
- 字串字尾相關字串
- 異常處理及其相關知識點
- 一道與 for 相關的字串面試題字串面試題
- 滑動視窗相關的題目總結
- leetcode 1525 字串的好分割數目(雜湊表,字串分割)LeetCode字串
- dfs題目這樣去接題,秒殺leetcode題目LeetCode
- 目錄處理命令
- 字串的相關函式字串函式
- 【C++】“反轉連結串列”相關的題目C++
- 【LeetCode】簡單題目集LeetCode
- 創新實訓(七)部落格相關功能介紹及內部邏輯處理
- bat 批處理字串操作BAT字串
- 簡單的字串處理字串
- shell字串處理總結字串
- Guava字串處理Joiner、SplitterGuava字串
- PHP 陣列 & 字串處理PHP陣列字串
- 二、Git 問題彙總及處理Git
- LeetCode題目:39. 組合總和 解題思路及Java實現LeetCodeJava
- openGauss資料庫xlog目錄滿問題處理資料庫
- 爬蟲入門(字串相關)爬蟲字串
- 【LeetCode動態規劃#10】完全揹包問題實戰,其三(單詞拆分,涉及集合處理字串)LeetCode動態規劃字串
- 【Leetcode】題目集:31-40LeetCode
- 『忘了再學』Shell基礎 — 31、字元處理相關命令字元
- 幾個與文字處理相關的Linux命令總結Linux
- 對於數字或者字串有限的問題的處理字串