February 04, 2023

Leetcode | Algorithm - KMP

Notes: KMP (Knuth Morris Pratt). reference here.

Introduction

字串尋找演算法 (KMP), 可在一個字串中尋找另一個字串的出現位子, 使用這個算法的平均時間複雜度是 O(n+m), 其中 n 為字串的長度, m 為模式串的長度.

Brute Force

我們先看看暴力解如何去解,假設有兩個字串:

  1. text: “aabaabaaf”
  2. pattern: “aabaaf”

最值觀的寫法就是從 text 開始做 for loop, 接下來逐字匹配 text, 如果 pattern 找到匹配失敗的 text 才往前移動 1 直到能將 pattern 匹配完或者 traverse text 結束. 在這種寫法下時間複雜度為 O(m*n), 因為至少每個 text 的 element 都要經過一次 pattern 的匹配過程. 也可以想像成一個滑動的窗口, 窗口的大小為 pattern size.

28. Find the Index of the First Occurrence in a String 中的暴力解法.

func strStr(haystack string, needle string) int {
	var result int = -1
	if len(haystack) < len(needle) {
		return result
	}
	for i := 0; i < len(haystack); i++ {
		if checkStr(haystack, needle, i) {
			result = i
			return result
		}
	}
	return result
}

func checkStr(haystack, needle string, index int) bool {
	for i := 0; i <= len(needle); i++ {
		if i == len(needle) {
			return true
		}
		if index >= len(haystack) {
			return false
		}
		if haystack[index] == needle[i] {
			index++
		} else {
			return false
		}
	}
	return false
}

KMP Algorithm

Diagram reference

因此我們可以將暴力解用圖解來展開:

那我們就能想像如何減少不必要的搜尋, 首先如下兩張圖: 如果右移後的 overlap 都無法比對, 下次比對時我們都可以先跳過這些 overlap.

但是看下面這個例子, 這次比對到的目標中含有符合的子串. 因此我們就有必要進一步的比對,

那這段 overlap 要如何找出來? 假設已經比對成功的部分是 p’, 他是 p 的一個子串, 那重疊部分就是 p’ tail 和右移 p’ 的head. 因此我們可以說

結合以上的兩種方式, 我們可以看到這個算法最終的樣子:

Last Edit

04-02-2023 19:28

results matching ""

    No results matching ""

    , algorithm, string