BF 暴力匹配
代码实现
func Search(p string,t string)int{
m := len(p)
n := len(t)
for i:=0;i<n-m;i++{
j := 0
for j=0;j<m;j++{
if p[j] != t[i+j]{break}
}
//全都匹配
if j == m{
return i
}
}
return -1
}
BM 算法
特点是当不匹配的时候 一次性可以跳过不止一个字符
那它是利用了什么特性去 排除尽可能多的无法匹配的位置 呢?
- bad-character shift 坏字符串规则:移动的位数 = 坏字符在模式串p中的位置-坏字符串在模式串中最右出现的位置
- good-suffix shift 好后缀规则:后移位数 = 好后缀在模式串中的位置-好后缀在模式串上一次出现的位置,
KMP 算法
先在开头约定,本文用pat表示模式串,长度为M,txt表示文本串,长度为N。KMP 算法是在txt中查找子串pat,如果存在,返回这个子串的起始索引,否则返回 -1。
为什么我认为 KMP 算法就是个动态规划问题呢?
KMP 算法永不回退txt的指针i,不走回头路(不会重复扫描txt),而是借助dp数组中储存的信息把pat移到正确的位置继续匹配,时间复杂度只需 O(N),用空间换时间,所以我认为它是一种动态规划算法。
计算这个dp数组,只和pat串有关
代码实现
// 这个方法没搞懂
var dp [][]int
var p string
func Search(t string)int{
m := len(p)
n := len(t)
//p的初始态为0
j := 0
for i:=0;i<n;i++{
//计算p的下一个状态
j = dp[j][t[i]]
if j == m{
return i-m+1
}
}
return -1
}
func KMP(p string){
m := len(p)
//dp[状态][字符]=下个状态
dp[0][p[0]] = 1
//影子状态X初始为0
x := 0
//构建状态转移方程
for j:=1;j<m;j++{
for c:=0;c<256;c++{
dp[j][c] = dp[x][c]
}
dp[j][p[j]] = j+1
//更新影子状态
x = dp[x][p[j]]
}
}
书上介绍的解题思路
package main
import "fmt"
func GetNext(T string, next []int){
length := len(T)
i:=1
j:=0
next[0] = 0
for i<length{
if j==0 || T[i-1]==T[j-1]{ //T[i]表示后缀字符 T[j]表示前缀字符
if T[i]!=T[j]{
next[i]=j+1
}else {
next[i] = next[j]
}
j++
i++
}else {
j = next[j-1]
}
}
}
// 返回子串T在主串S中第pos个字符之后的位置。若不存在则函数返回值为0
func IndexKMP(S string,T string,pos int)int{
lengthS := len(S)
lengthT := len(T)
i := pos //用于主串S当前位置下标值
j := 0 //用于子串T当前位置下标值
next := []int{0,0,0,0,0,0,0,0,0}
GetNext(T,next)
fmt.Println(next,i,j)
for i<lengthS && j<lengthT{
if j==0 || S[i] == T[j]{
//fmt.Println(S[i],T[j])
i++
j++
}else {
j = next[j-1] //j退回合适的位置
}
}
//fmt.Println(j ,lengthT)
if j>lengthT-1{
return i-lengthT
}else {
return 0
}
}
func main(){
S := "abvvvabcabc"
//T := "bbbbbbbba"
T := "ababaaaba"
res := IndexKMP(S,T,0)
fmt.Println(res)
}