KMP算法——在文本串中找模式串第一次出现的位置

219 阅读1分钟

在计算机科学中,Knuth-Morris-Pratt字符串查找算法(简称为KMP算法)可在一个字符串 S 内查找一个词 W 的出现位置(也可以在S中获取W出现的次数)。一个词在不匹配时本身就包含足够的信息来确定下一个匹配可能的开始位置,此算法利用这一特性以避免重新检查先前匹配的字符。

// 在text中找pattern第一次出现的索引。如果没找到就返回-1。
// 约定:只要pattern是空字符串,就返回0
func FirstIndex(text, pattern string) int {
    if pattern == "" {
        return 0
    } else if text == "" {
        return -1
    }
    // text != "" && pattern != ""
    var (
        tl = len(text)
        pl = len(pattern)
    )
    if tl < pl {
        return -1
    }
    // tl >= pl
    return indexKMP(text, pattern)
}

func indexKMP(text, pattern string) int {
    var (
        ti int
        pi int
        tl = len(text)
        pl = len(pattern)
        next = getNextArray(pattern)
    )
    for ti < tl {
        if text[ti] == pattern[pi] {
            ti++
            pi++
            if pi == pl {
                return ti-pl
            }
        } else if pi == 0 {
            ti++
            if tl-ti < pl {
                break
            }
        } else {
            pi = next[pi-1]
            if tl-ti < pl-pi {
                break
            }
        }
    }
    return -1
}

func getNextArray(p string) []int {
    // 前置条件: p不是空字符串
    if p == "" {
        panic("p is empty")
    }
    var (
        j    int // 前缀当前索引
        i    = 1 // 后缀当前索引
        l    = len(p)
        next = make([]int, l)
    )
    // next[0] = 0,隐含的初始化
    for i < l {
        if p[j] == p[i] {
            j++
            next[i] = j
            i++
        } else if j == 0 {
            next[i] = 0
            i++
        } else {
            j = next[j-1]
        }
    }
    return next
}