forked from wangzheng0822/algo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstring_bm.go
140 lines (107 loc) · 2.24 KB
/
string_bm.go
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package main
import (
"fmt"
"math"
)
//bc: pattern char index hash mapping
func generateBC(pattern string) []int {
bc := make([]int, 256)
for index := range bc {
bc[index] = -1
}
for index, char := range pattern {
bc[int(char)] = index
}
return bc
}
//generate suffix and prefix array for pattern
func generateGS(pattern string) ([]int, []bool) {
m := len(pattern)
suffix := make([]int, m)
prefix := make([]bool, m)
//init
for i := 0; i < m; i++ {
suffix[i] = -1
prefix[i] = false
}
for i := 0; i < m-1; i++ {
j := i
k := 0
for j >= 0 && pattern[j] == pattern[m-1-k] {
j--
k++
suffix[k] = j + 1
}
if j == -1 {
prefix[k] = true
}
}
return suffix, prefix
}
//todo
func moveByGS(patternLength int, badCharStartIndex int, suffix []int, prefix []bool) int {
//length of good suffix
k := patternLength - badCharStartIndex - 1
//complete match
if suffix[k] != -1 {
return badCharStartIndex + 1 - suffix[k]
}
//partial match
for t := patternLength - 1; t > badCharStartIndex+1; t-- {
if prefix[t] {
return t
}
}
//no match
return patternLength
}
func bmSearch(main string, pattern string) int {
//defensive
if len(main) == 0 || len(pattern) == 0 || len(pattern) > len(main) {
return -1
}
bc := generateBC(pattern)
suffix, prefix := generateGS(pattern)
n := len(main)
m := len(pattern)
// i : start index of main string
step := 1
for i := 0; i <= n-m; i = i + step {
subStr := main[i : i+m]
k, j := findBadChar(subStr, pattern, bc)
stepForBC := j - k
//j is bad char occur index
if j == -1 {
return i
}
stepForGS := -1
if j < m-1 {
stepForGS = moveByGS(m, j, suffix, prefix)
}
//k is bad char index in pattern
step = int(math.Max(float64(stepForBC), float64(stepForGS)))
}
return -1
}
func findBadChar(subStr string, pattern string, bc []int) (int, int) {
j := -1
k := -1
badChar := rune(0)
for index := len(subStr) - 1; index >= 0; index-- {
if subStr[index] != pattern[index] {
j = index
badChar = rune(subStr[index])
break
}
}
//if bad character exist, then find it's index at pattern
if j > 0 {
k = bc[int(badChar)]
}
return k, j
}
func main() {
main := "abcacabcbcabcabc"
pattern := "cabcab"
fmt.Println(bmSearch(main, pattern))
}