這是一種類似於KMP但是更高效一點、也更簡單一些的字符串查找算法,大體的思路是從右往左掃描,例如在txt = ABCBCDCDE中查找模式串pat = BCD,
ABCBCDCDE
BCD
從右往左,第一個比較的字符是 C 和 D ,不匹配,C 在 BCD 裏出現的所有位置中最靠右是 1,那麼 BCD 右移 1 位,比較 B 和 D ,
ABCBCDCDE
BCD
不匹配,B 在 BCD裏出現的所有位置中最靠右是 0,那麼BCD右移 2 位,
ABCBCDCDE
BCD
匹配成功,當然例子有些簡單,看完以下的具體規則後,就會消除你所有的顧慮 = =!
具體的規則如下:( i 是 txt 中的遊標,j 是 pat 中的遊標)
1. 如果失配字符不在 pat 中,那麼 pat 右移 j+1 個位置,也就是 i += j+1 繼續比較。這條應該是淺顯易懂,不懂得在紙上畫一下就知道了。
2. 如果失配字符在 pat 中,那麼 pat 右移,使得適配字符與 pat 中該字符出現的所有位置中最右的那個對齊,即右移 j - x 即 i += j - x ,x 即是最右位置。
3. 如果以上兩條不能使 i 增大,i += 1。
以上第 2 條的 x 可以通過預處理來提前計算好,計算的代碼如下:
int right[256];
memset(right, -1, sizeof(int) * 256);// 初始化爲-1
for (int k = 0; k < strlen(pat); ++k) {
right[pat[k]] = k;
}
查找代碼如下:
int skip = 0;
for (int i = 0; i < strlen(txt) - strlen(pat); i += skip) {
skip = 0;
for (int j = (int)strlen(pat)-1; j >= 0; --j) {
if (txt[i+j] != pat[j]) { // 字符匹配失敗
skip = j - right[pat[j]];
if (skip < 1) { // i 無法增大
skip += 1;
}
break;
}
}
if (skip == 0) { // 全部匹配成功
return i;
}
}
PS:可以根據KMP的思路,優化一下,即已經匹配過的,是不是有相同的串。
參考:《算法》第四版