github.com/qiuhoude/go-web@v0.0.0-20220223060959-ab545e78f20d/algorithm/datastructures/bm/bm.go (about) 1 package bm 2 3 /* 4 bm 字符匹配算法 Boyer-Moore 5 1. 好串规则 bad character rule 好串表示已匹配字符 6 2. 坏串规则 good suffix shift 坏串表示不匹配字符 7 */ 8 9 // 构建 k:字符 v:位置 的hash表 10 func generateBc(b []rune) map[rune]int { 11 ret := make(map[rune]int, len(b)) 12 for index, v := range b { 13 ret[v] = index 14 } 15 return ret 16 } 17 18 // 返回第一个匹配的位置 19 func BmSearch(mainStr, pattern []rune) int { 20 if len(mainStr) == 0 || len(pattern) == 0 || len(pattern) > len(mainStr) { 21 return -1 22 } 23 //构建坏字符哈希表 24 bc := generateBc(pattern) 25 n := len(mainStr) 26 m := len(pattern) 27 suffix, prefix := generateGS(pattern) 28 step := 1 29 // 主串与模式对齐的第一个字符的位置 30 for i := 0; i <= n-m; i += step { 31 32 //查找坏字符串的位置 33 badCharIndex := m - 1 // badCharIndex 表示坏字符在模式串的位置 34 for ; badCharIndex >= 0; badCharIndex-- { // 从后往前进行匹配 35 if mainStr[i+badCharIndex] != pattern[badCharIndex] { 36 break //找到了坏字符的位置 37 } 38 } 39 40 if badCharIndex <= 0 { 41 // 没有坏串就匹配成功,返回主串与模式串第一个匹配的字符的位置 42 return i 43 /* 44 // 如果此处如果要继续匹配 45 step =1 46 continue 47 */ 48 } 49 /* 50 1. 坏串规则: 51 i+badCharIndex是坏字符在主串的位置, mainStr[i+badCharIndex]就是坏串的字符 52 bc[mainStr[i+badCharIndex]]就是坏串字符在模式串的位置 没有就是 -1 53 badCharIndex-bc[mainStr[i+badCharIndex]] 就是要向后滑动的距离 54 */ 55 bcIndex := -1 56 if i, ok := bc[mainStr[i+badCharIndex]]; ok { 57 bcIndex = i 58 } 59 stepForBC := badCharIndex - bcIndex // 坏串滑动位数 60 61 /* 62 2. 好串规则 63 */ 64 stepForGS := -1 65 if badCharIndex < m-1 { //如果有好串后缀 66 stepForGS = moveByGS(badCharIndex, m, suffix, prefix) // 计算位移 67 } 68 // 向后移动位置 69 step = max(stepForBC, stepForGS) 70 if step <= 0 { // 防止负数 71 step = 1 72 } 73 } 74 return -1 75 } 76 77 func max(a, b int) int { 78 if a > b { 79 return a 80 } 81 return b 82 83 } 84 85 // badChartIndex 表示坏字符在模式串中的位置 ; m 表示模式串长度 86 func moveByGS(badCharIndex, patternLen int, suffix []int, prefix []bool) int { 87 k := patternLen - 1 - badCharIndex // k 已经匹配后缀的长度 88 if suffix[k] != -1 { //complete match 直接找到位置了 89 return badCharIndex - suffix[k] + 1 90 } 91 92 // 否则匹配后缀子串 93 for r := badCharIndex + 2; r < patternLen-1; r++ { 94 // 95 if prefix[patternLen-r] { // patternLen-r 表示后缀子串的长度 96 return r 97 } 98 } 99 //no match 100 return patternLen 101 } 102 103 // 返回好串 后缀表 与 前缀表 104 func generateGS(b []rune) ([]int, []bool) { 105 m := len(b) 106 // 存储的是该位置的字符,当前位置倒数上一次出现的位置的下标 107 // cabcab 最后一个b index=5,只有1个字符 ,上一次出现的b index=2, 108 // 所以 suffix[1]=2 109 suffix := make([]int, m) 110 // 后缀子串与前缀子串的位置是否匹配 111 prefix := make([]bool, m) 112 for i := 0; i < m; i++ { 113 suffix[i] = -1 114 prefix[i] = false 115 } 116 for i := 0; i < m-1; i++ { //b[0;i] 117 // 此处从后往前数的指针 118 j := i // 从 j 位置往前数 119 k := 0 120 for j >= 0 && b[j] == b[m-1-k] { // 与 b[0, m-1] 求公共后缀子串 121 // m-1-k 理解为从末尾往前数 122 j-- 123 k++ 124 // k 表示长度 125 suffix[k] = j + 1 //j+1 表示公共后缀子串在 b[0, i] 中的起始下标 126 } 127 if j == -1 { 128 prefix[k] = true // 如果公共后缀子串也是模式串的前缀子串 129 } 130 } 131 return suffix, prefix 132 }