Skip to content

Commit 51aa66d

Browse files
committed
Init Solution for challenge 23
1 parent a7ac764 commit 51aa66d

File tree

1 file changed

+199
-0
lines changed

1 file changed

+199
-0
lines changed
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
func main() {
8+
// Sample texts and patterns
9+
testCases := []struct {
10+
text string
11+
pattern string
12+
}{
13+
{"ABABDABACDABABCABAB", "ABABCABAB"},
14+
{"AABAACAADAABAABA", "AABA"},
15+
{"GEEKSFORGEEKS", "GEEK"},
16+
{"AAAAAA", "AA"},
17+
}
18+
19+
// Test each pattern matching algorithm
20+
for i, tc := range testCases {
21+
fmt.Printf("Test Case %d:\n", i+1)
22+
fmt.Printf("Text: %s\n", tc.text)
23+
fmt.Printf("Pattern: %s\n", tc.pattern)
24+
25+
// Test naive pattern matching
26+
naiveResults := NaivePatternMatch(tc.text, tc.pattern)
27+
fmt.Printf("Naive Pattern Match: %v\n", naiveResults)
28+
29+
// Test KMP algorithm
30+
kmpResults := KMPSearch(tc.text, tc.pattern)
31+
fmt.Printf("KMP Search: %v\n", kmpResults)
32+
33+
// Test Rabin-Karp algorithm
34+
rkResults := RabinKarpSearch(tc.text, tc.pattern)
35+
fmt.Printf("Rabin-Karp Search: %v\n", rkResults)
36+
37+
fmt.Println("------------------------------")
38+
}
39+
}
40+
41+
// NaivePatternMatch performs a brute force search for pattern in text.
42+
// Returns a slice of all starting indices where the pattern is found.
43+
func NaivePatternMatch(text, pattern string) []int {
44+
// Convert text and pattern to rune
45+
rText := []rune(text)
46+
rPattern := []rune(pattern)
47+
48+
// Calculate rune length
49+
lenPattern := len(rPattern)
50+
lenText := len(rText)
51+
52+
// Check for emty text pattern and pattern no more than text
53+
if text == "" || pattern == "" || lenPattern > lenText {
54+
return []int{}
55+
}
56+
57+
// Init result slise
58+
res := []int{}
59+
60+
// Loop through the text
61+
for i := 0; i <= lenText-lenPattern; i++ {
62+
match := true
63+
64+
// loop through the pattern and text to compare each rune
65+
for j := range lenPattern {
66+
if rText[i+j] != rPattern[j] {
67+
match = false
68+
break
69+
}
70+
}
71+
72+
// If loop ends without breaks and match it true - append index to result
73+
if match {
74+
res = append(res, i)
75+
}
76+
}
77+
return res
78+
}
79+
80+
// KMPSearch implements the Knuth-Morris-Pratt algorithm to find pattern in text.
81+
// Returns a slice of all starting indices where the pattern is found.
82+
func KMPSearch(text, pattern string) []int {
83+
// Convert text and pattern to rune
84+
rText := []rune(text)
85+
rPattern := []rune(pattern)
86+
87+
// Calculate rune length
88+
lenPattern := len(rPattern)
89+
lenText := len(rText)
90+
91+
// Check for emty text pattern and pattern no more than text
92+
if text == "" || pattern == "" || lenPattern > lenText {
93+
return []int{}
94+
}
95+
96+
// init lps slise
97+
res := []int{}
98+
lps := make([]int, len(pattern))
99+
i := 1
100+
l := 0
101+
102+
// Loop through the pattern to calculate LPS slise
103+
for i < lenPattern {
104+
if rPattern[l] == rPattern[i] {
105+
l++
106+
lps[i] = l
107+
i++
108+
} else {
109+
if l != 0 {
110+
l = lps[l-1]
111+
// l--
112+
} else {
113+
lps[i] = 0
114+
i++
115+
}
116+
}
117+
}
118+
119+
// Loop for KMP search
120+
i, j := 0, 0
121+
for i < lenText {
122+
if rText[i] == rPattern[j] {
123+
i++
124+
j++
125+
}
126+
if j == lenPattern {
127+
res = append(res, i-j)
128+
j = lps[j-1]
129+
} else if i < lenText && text[i] != pattern[j] {
130+
if j != 0 {
131+
j = lps[j-1]
132+
} else {
133+
i++
134+
}
135+
}
136+
}
137+
return res
138+
}
139+
140+
// RabinKarpSearch implements the Rabin-Karp algorithm to find pattern in text.
141+
// Returns a slice of all starting indices where the pattern is found.
142+
func RabinKarpSearch(text, pattern string) []int {
143+
const base = 256
144+
const mod = 101 // prime number
145+
146+
// init res slise
147+
res := []int{}
148+
149+
// Convert text and pattern to rune
150+
rText := []rune(text)
151+
rPattern := []rune(pattern)
152+
153+
// Calculate rune length
154+
lenPattern := len(rPattern)
155+
lenText := len(rText)
156+
157+
// Check for emty text pattern and pattern no more than text
158+
if text == "" || pattern == "" || lenPattern > lenText {
159+
return []int{}
160+
}
161+
162+
var patternHash, textHash, h int
163+
164+
// Calculate hash for pattern h = base^(m-1) % mod
165+
h = 1
166+
for i := 0; i < lenPattern-1; i++ {
167+
h = (h * base) % mod
168+
}
169+
170+
// Initial hash
171+
for i := range lenPattern {
172+
patternHash = (base*patternHash + int(pattern[i])) % mod
173+
textHash = (base*textHash + int(text[i])) % mod
174+
}
175+
176+
for i := 0; i <= lenText-lenPattern; i++ {
177+
if patternHash == textHash {
178+
match := true
179+
for j := range lenPattern {
180+
if text[i+j] != pattern[j] {
181+
match = false
182+
break
183+
}
184+
}
185+
if match {
186+
res = append(res, i)
187+
}
188+
}
189+
190+
if i < lenText-lenPattern {
191+
textHash = (base*(textHash-int(text[i])*h) + int(text[i+lenPattern])) % mod
192+
if textHash < 0 {
193+
textHash += mod
194+
}
195+
}
196+
}
197+
198+
return res
199+
}

0 commit comments

Comments
 (0)