1. 程式人生 > 實用技巧 >實現 Trie (字首樹)

實現 Trie (字首樹)

題目:

實現一個 Trie (字首樹),包含insert,search, 和startsWith這三個操作。

Trie trie = new Trie();

trie.insert("apple");
trie.search("apple");   // 返回 true
trie.search("app");     // 返回 false
trie.startsWith("app"); // 返回 true
trie.insert("app");   
trie.search("app");     // 返回 true

思路:

Trie 樹的結點結構

Trie 樹是一個有根的樹,其結點具有以下欄位:

  • 最多 R 個指向子結點的連結,其中每個連結對應字母表資料集中的一個字母。本文中假定 R 為 26,小寫拉丁字母的數量。
  • 布林欄位,以指定節點是對應鍵的結尾還是隻是鍵字首。

Trie 樹中最常見的兩個操作是鍵的插入和查詢。

向 Trie 樹中插入鍵

我們通過搜尋 Trie 樹來插入一個鍵。我們從根開始搜尋它對應於第一個鍵字元的連結。有兩種情況:

  • 連結存在。沿著連結移動到樹的下一個子層。演算法繼續搜尋下一個鍵字元。
  • 連結不存在。建立一個新的節點,並將它與父節點的連結相連,該連結與當前的鍵字元相匹配。

重複以上步驟,直到到達鍵的最後一個字元,然後將當前節點標記為結束節點,演算法完成。

在 Trie 樹中查詢鍵

每個鍵在 trie 中表示為從根到內部節點或葉的路徑。我們用第一個鍵字元從根開始,。檢查當前節點中與鍵字元對應的連結。有兩種情況:

  • 存在連結。我們移動到該連結後面路徑中的下一個節點,並繼續搜尋下一個鍵字元。
  • 不存在連結。若已無鍵字元,且當前結點標記為 isEnd,則返回 true。否則有兩種可能,均返回 false :
    • 還有鍵字元剩餘,但無法跟隨 Trie 樹的鍵路徑,找不到鍵。
    • 沒有鍵字元剩餘,但當前結點沒有標記為 isEnd。也就是說,待查詢鍵只是Trie樹中另一個鍵的字首。

查詢 Trie 樹中的鍵字首

該方法和查詢基本相似,甚至更簡單因為不需要考慮當前 Trie 節點是否用 “isend” 標記,因為我們搜尋的是鍵的字首,而不是整個鍵。

程式碼
package main

import "fmt"

type Trie struct {
	next [26]*Trie
	isEnd bool
}


/** Initialize your data structure here. */
func Constructor() *Trie {
	return &Trie{}
}


/** Inserts a word into the trie. */
func (this *Trie) Insert(word string)  {
	for _, v := range word {
		if this.next[v-'a'] == nil {
			this.next[v-'a'] = new(Trie)
			this = this.next[v-'a']
		}else {
			this = this.next[v-'a']
		}
	}
	this.isEnd = true
}


/** Returns if the word is in the trie. */
func (this *Trie) Search(word string) bool {
	for _, v := range word {
		if this.next[v-'a'] == nil {
			return false
		}
		this = this.next[v-'a']
	}
	if this.isEnd == false {
		return false
	}
	return true
}


/** Returns if there is any word in the trie that starts with the given prefix. */
func (this *Trie) StartsWith(prefix string) bool {
	for _, v := range prefix {
		if this.next[v-'a'] == nil {
			return false
		}
		this = this.next[v-'a']
	}
	return true
}

func main() {

	trie := Constructor()

	trie.Insert("apple");

	fmt.Println(trie.Search("apple"))  // 返回 true
	fmt.Println(trie.Search("app"))     // 返回 false
	fmt.Println(trie.StartsWith("app")) // 返回 true
	trie.Insert("app")
	fmt.Println(trie.Search("app"))     // 返回 true

}

  地址:https://mp.weixin.qq.com/s/qkM88Ok-SY-QjoI-6hVCOw