hash(bcd) = hash(bc)*26 + hash(d)
= (hash(abc) - hash(a)的部分)*26 + hash(d)
= (hash(abc) - hash(a)*26²)*26 + hash(d)
func rabinKarp(haystack string, needle string) int {
if len(haystack) < len(needle) {
return -1
}
base := 26 // 进制,假设输入只包含26个字母,这里就可以使用26进制
mod := int(1e5) // 为防止 int 溢出取模
l := len(needle)
targetHash := 0 // 要查找的 hash
curHash := 0 // 当前比对字符串的 hash
// shift 用于算最高位有几次方,用于算滚动 hash 时扣减最高位。比如 hash(abc) = a*26² + b*26 + c,则 shift = 26²
shift := 1
// 计算初始 hash
for i := range needle {
if i > 0 {
shift = shift * base % mod
}
targetHash = (targetHash*base + byteToInt(needle[i])) % mod
curHash = (curHash*base + byteToInt(haystack[i])) % mod
}
// 这里第一步 i 是 exclude 的,因此条件为 <=
for i := len(needle); i <= len(haystack); i++ {
// 1. 比对 hash 和原始字符串
if curHash == targetHash && haystack[i-l:i] == needle {
return i - len(needle)
}
// 2. 计算滚动 hash
if i < len(haystack) {
curHash = ((curHash-(byteToInt(haystack[i-l])*shift))*base + byteToInt(haystack[i])) % mod
if curHash < 0 {
curHash += mod
}
}
}
return -1
}
func byteToInt(b byte) int {
return int(b - 'a')
}