LeetCode-题目整理【9】:Trie树

最长公共前缀可以使用字典树来解答,在解答中,需要查找单词,如果有精确需要查找的单词word,那么可以使用代码:

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
}

但是如果查找的单词不明确,那么可以使用代码(以公共前缀为例):

func (node *TrieNode) search() string {
	prefix := ""
	for node.countChildren() == 1 && !node.isEnd {
	
	//就是这个位置,可以遍历字典树中的字母,如果当前字母不为空,可以继续往下遍历
		for i := 0; i < 26; i++ {
			if node.next[i] != nil {
				prefix = prefix + string('a'+ i)
				node = node.next[i]
				break
			}
		}
	}
	
	return prefix
}

    // 计算当前节点子节点的数量
func (node *TrieNode) countChildren() int {
	......
}
  1. 最长公共前缀
    简单
    编写一个函数来查找字符串数组中的最长公共前缀。
    如果不存在公共前缀,返回空字符串 “”。
    示例 1:
    输入:strs = [“flower”,“flow”,“flight”]
    输出:“fl”
    示例 2:
    输入:strs = [“dog”,“racecar”,“car”]
    输出:“”
    解释:输入不存在公共前缀。
//字符串
// 函数首先找到长度最短的字符串,然后逐个比较字符,如果遇到不相同的字符,则返回当前索引之前的字符串作为结果。
//这是一个更简洁的实现,它的时间复杂度是O(n*m),其中n是字符串数组的长度,m是字符串的平均长度。

func longestCommonPrefix(strs []string) string {
	if len(strs) == 0 {
		return ""
	}

	minstr := strs[0]

	for _, str := range strs {
		if len(str) < len(minstr) {
			minstr = str
		}
	}

	for i := 0; i < len(minstr); i++ {
		curStr := strs[0][i]
		for _, str := range strs {
			if str[i] != curStr {
				return strs[0][:i]
			}
		}
	}

	return strs[0][:len(minstr)]
}
//使用字典树
type TrieNode struct {
	next  [26]*TrieNode
	isEnd bool
}

func longestCommonPrefix(strs []string) string {
	root := &TrieNode{}

	//构建字典树
	for _, str := range strs {
		root.Insert(str)
	}

	//查找最长公共前缀
	return root.search()
}

// 插入字符
func (node *TrieNode) Insert(word string) {
	for _, v := range word {
		if node.next[v-'a'] == nil {
			node.next[v-'a'] = &TrieNode{}
		}
		node = node.next[v-'a']
	}
	node.isEnd = true
}

    //查找字符和公共前缀
func (node *TrieNode) search() string {
	prefix := ""

	//当前节点的子节点数量为1(如果大于1,表示节点之后会有分叉,就不是公共节点)
	//且当前节点不是一个单词的结束节点,就继续循环。
	for node.countChildren() == 1 && !node.isEnd {
		for i := 0; i < 26; i++ {
			if node.next[i] != nil {
				prefix = prefix + string('a'+ i)
				node = node.next[i]
				break
			}
		}
	}

	return prefix
}

    // 计算当前节点子节点的数量
func (node *TrieNode) countChildren() int {
	count := 0
	for i := 0; i < 26; i++ {
		if node.next[i] != nil {
			count++
		}
	}
	return count
}

  1. 实现 Trie (前缀树)
    中等
    Trie(发音类似 “try”)或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。
    请你实现 Trie 类:
    Trie() 初始化前缀树对象。
    void insert(String word) 向前缀树中插入字符串 word 。
    boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。
    boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。
    示例:
    输入
    [“Trie”, “insert”, “search”, “search”, “startsWith”, “insert”, “search”]
    [[], [“apple”], [“apple”], [“app”], [“app”], [“app”], [“app”]]
    输出
    [null, null, true, false, true, null, true]
    解释
    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
type Trie struct {
	next  [26]*Trie
	isEnd bool
}

func Constructor() Trie {
	return 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']
	}
	this.isEnd = true
}

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
}

//前提是已经知道 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
}

/**
 * Your Trie object will be instantiated and called as such:
 * obj := Constructor();
 * obj.Insert(word);
 * param_2 := obj.Search(word);
 * param_3 := obj.StartsWith(prefix);
 */

下面这道题解答过程和 “实现 Trie (前缀树)” 的insert和search基本一样,主要区别在于查找单词时,多了条件:word 中可能包含一些 ‘.’ ,每个 . 都可以表示任何一个字母。
多添加的代码是判断"."的情况:

if char == '.' {
			for _, v := range this.next {
				if v != nil && v.search(word, i+1) {
					return true
				}
			}
			return false
		}
  1. 添加与搜索单词 - 数据结构设计
    中等
    请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。
    实现词典类 WordDictionary :
    WordDictionary() 初始化词典对象
    void addWord(word) 将 word 添加到数据结构中,之后可以对它进行匹配
    bool search(word) 如果数据结构中存在字符串与 word 匹配,则返回 true ;否则,返回 false 。word 中可能包含一些 ‘.’ ,每个 . 都可以表示任何一个字母。
    示例:
    输入:
    [“WordDictionary”,“addWord”,“addWord”,“addWord”,“search”,“search”,“search”,“search”]
    [[],[“bad”],[“dad”],[“mad”],[“pad”],[“bad”],[“.ad”],[“b…”]]
    输出:
    [null,null,null,null,false,true,true,true]
    解释:
    WordDictionary wordDictionary = new WordDictionary();
    wordDictionary.addWord(“bad”);
    wordDictionary.addWord(“dad”);
    wordDictionary.addWord(“mad”);
    wordDictionary.search(“pad”); // 返回 False
    wordDictionary.search(“bad”); // 返回 True
    wordDictionary.search(“.ad”); // 返回 True
    wordDictionary.search(“b…”); // 返回 True
type WordDictionary struct {
	next  [26]*WordDictionary
	isEnd bool
}

func Constructor() WordDictionary {
	return WordDictionary{}
}

func (this *WordDictionary) AddWord(word string) {
	for _, v := range word {
		if this.next[v-'a'] == nil {
			this.next[v-'a'] = new(WordDictionary)
		}
		this = this.next[v-'a']
	}
	this.isEnd = true
}

func (this *WordDictionary) Search(word string) bool {
	return this.search(word, 0)
}

func (this *WordDictionary) search(word string, index int) bool {
	for i := index; i < len(word); i++ {
		char := word[i]
		//多了判断"."的情况,其他基本一致
		if char == '.' {
			for _, v := range this.next {
				if v != nil && v.search(word, i+1) {
					return true
				}
			}
			return false
		}
		if this.next[char-'a'] == nil {
			return false
		}
		this = this.next[char-'a']
	}
	if this.isEnd == false {
		return false
	}
	return true
}

/**
 * Your WordDictionary object will be instantiated and called as such:
 * obj := Constructor();
 * obj.AddWord(word);
 * param_2 := obj.Search(word);
 */

你可能感兴趣的:(leetcode,算法,go)