package main import "fmt" func naiveSearch(text, pattern string) []int { var result []int n, m := len(text), len(pattern) for i := 0; i <= n-m; i++ { j := 0 for j < m && text[i+j] == pattern[j] { j++ } if j == m { result = append(result, i) } } return result } func main() { text := "abracadabra" pattern := "abra" fmt.Println(naiveSearch(text, pattern)) }
The naive search checks every position in the text where the pattern could start. The pattern "abra" appears at index 0 and again at index 7 in "abracadabra". So the output is [0 7].
package main import "fmt" func buildLPS(pattern string) []int { lps := make([]int, len(pattern)) length := 0 i := 1 for i < len(pattern) { if pattern[i] == pattern[length] { length++ lps[i] = length i++ } else { if length != 0 { length = lps[length-1] } else { lps[i] = 0 i++ } } } return lps } func main() { pattern := "ababaca" fmt.Println(buildLPS(pattern)) }
The prefix table for "ababaca" is [0 0 1 2 3 0 1]. This means at each index, the length of the longest proper prefix which is also suffix is stored.
package main import "fmt" func rabinKarpUpdateHash(oldHash int, leftChar, rightChar byte, h, q int) int { newHash := (oldHash - int(leftChar)*h) * 256 newHash = (newHash + int(rightChar)) % q if newHash < 0 { newHash += q } return newHash } func main() { oldHash := 100 leftChar := byte('a') rightChar := byte('b') h := 1 q := 101 fmt.Println(rabinKarpUpdateHash(oldHash, leftChar, rightChar, h, q)) }
The variable h should be precomputed as (256^(m-1)) % q where m is the pattern length. Here h=1 is incorrect, so the hash update will produce wrong values.
KMP runs in linear time relative to the sum of text and pattern lengths, so O(n + m).
package main import "fmt" func rabinKarpSearch(text, pattern string) []int { var result []int n, m := len(text), len(pattern) if m > n { return result } q := 101 h := 1 for i := 0; i < m-1; i++ { h = (h * 256) % q } pHash, tHash := 0, 0 for i := 0; i < m; i++ { pHash = (256*pHash + int(pattern[i])) % q tHash = (256*tHash + int(text[i])) % q } for i := 0; i <= n-m; i++ { if pHash == tHash { match := true for j := 0; j < m; j++ { if text[i+j] != pattern[j] { match = false break } } if match { result = append(result, i) } } if i < n-m { tHash = (256*(tHash-int(text[i])*h) + int(text[i+m])) % q if tHash < 0 { tHash += q } } } return result } func main() { text := "this is a test text with test cases" pattern := "test" fmt.Println(rabinKarpSearch(text, pattern)) }
The pattern "test" appears starting at index 10 and index 25 in the text. The Rabin-Karp algorithm finds these indices correctly.
