-
Notifications
You must be signed in to change notification settings - Fork 0
/
rabin_karp.rb
72 lines (57 loc) · 1.51 KB
/
rabin_karp.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# Rabin Karp
# https://en.wikipedia.org/wiki/Rabin-Karp_algorithm
module RabinKarp
def self.basic_index(s, pattern)
n = s.length
m = pattern.length
pattern_hash = hash_func(pattern)
(0..n-m).each do |i|
sub_str = s[i, m]
h = hash_func(sub_str)
return i if h == pattern_hash && sub_str == pattern
end
return nil
end
def self.index(s, pattern)
n = s.length
m = pattern.length
pattern_hash = hash_func(pattern)
old_sub_str = s[0, m]
h = hash_func(old_sub_str)
(0..n-m).each do |i|
sub_str = s[i, m]
h = rolling_hash_func(sub_str, old_sub_str, h) if i > 0
return i if h == pattern_hash && sub_str == pattern
old_sub_str = sub_str
end
return nil
end
def self.hash_func(s, base = 101)
rabin_fingerprint(s)
end
def self.rolling_hash_func(s, old_s, old_hash, base = 101)
n = s.length-1
old_char = old_s[0]
new_char = s[n]
hash = (old_hash - (old_char.ord * 101**n)) * base + new_char.ord
end
def self.rabin_fingerprint(s, base = 101)
r = 0
n = s.length-1
s.split('').each_with_index do |c,i|
r += c.ord * 101**(n-i)
end
r
end
end
def process_input(filename, pattern)
text = File.read(filename)
RabinKarp.index(text, pattern)
end
puts process_input(ARGV[0], ARGV[1]) if __FILE__==$0
# usage
# $ irb
# > require './algorithms/rabin_karp.rb'
# > RabinKarp.index('test if this works', 'test')
# or
# ruby algorithms/rabin_karp.rb examples/example.txt "George Washington"