一言以敝之,字典樹,屬於 Tree
的衍生資料結構。
結構上一樣有 root,視為起點,第一層為各個單字的第一個字母,接著依照單字的字母,依序填入。
第一層到任意 Leaf,都可以成為一個單字。
Implement a trie with
insert
,search
, andstartsWith
methods.Example:
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple"); // returns true
trie.search("app"); // returns false
trie.startsWith("app"); // returns true
trie.insert("app");
trie.search("app"); // returns true
Note:
- You may assume that all inputs are consist of lowercase letters a-z.
- All inputs are guaranteed to be non-empty strings.
沒錯,LeetCode 有一題專門要求答題者實作 Trie
,三個方法皆是 Trie
會使用到的基本方法。
JS
/**
* Initialize your data structure here.
*/
var TrieNode = function (key) {
return {
key: key,
isWord: false
};
};
var Trie = function () {
this.trie = {};
};
/**
* Inserts a word into the trie.
* @param {string} word
* @return {void}
*/
Trie.prototype.insert = function (word) {
let trie = this.trie;
for (let i = 0; i < word.length; i++) {
const char = word[i];
if (!trie[char]) {
trie[char] = {};
}
trie = trie[char];
}
trie.isEnd = true;
};
/**
* Returns if the word is in the trie.
* @param {string} word
* @return {boolean}
*/
Trie.prototype.search = function (word) {
let currentNode = this.trie;
for (let i = 0; i < word.length; i++) {
const char = word[i];
if (currentNode[char] === undefined) {
return false;
}
currentNode = currentNode[char];
}
return currentNode.isEnd === true;
};
/**
* Returns if there is any word in the trie that starts with the given prefix.
* @param {string} prefix
* @return {boolean}
*/
Trie.prototype.startsWith = function (prefix) {
let currentNode = this.trie;
for (let i = 0; i < prefix.length; i++) {
const char = prefix[i];
if (currentNode[char] === undefined) {
return false;
}
currentNode = currentNode[char];
}
return true;
};
Java
class Trie {
private Node root;
/** Initialize your data structure here. */
public Trie() {
root = new Node(false);
}
/** Inserts a word into the trie. */
public void insert(String word) {
Node node = root;
for (int i = 0; i < word.length(); ++i) {
char ch = word.charAt(i);
if (!node.children.containsKey(ch)) {
node.children.put(ch, new Node(false));
}
node = node.children.get(ch);
node.endOfWord |= (i == word.length() - 1);
}
}
/** Returns if the word is in the trie. */
public boolean search(String word) {
Node node = root;
for (int i = 0; i < word.length(); ++i) {
char ch = word.charAt(i);
node = node.children.get(ch);
if (null == node)
return false;
}
return node.endOfWord;
}
/**
* Returns if there is any word in the trie that starts with the given prefix.
*/
public boolean startsWith(String prefix) {
Node node = root;
for (int i = 0; i < prefix.length(); ++i) {
char ch = prefix.charAt(i);
node = node.children.get(ch);
if (null == node)
return false;
}
return true;
}
static class Node {
private Map<Character, Node> children;
private boolean endOfWord;
public Node(boolean endOfWord) {
this.endOfWord = endOfWord;
this.children = new HashMap<>();
}
}
}
C
#define ALPHABET_SIZE (26)
typedef struct
{
struct Trie *children[ALPHABET_SIZE];
bool isLeaf;
} Trie;
/** Initialize your data structure here. */
Trie *trieCreate()
{
Trie *newNode = malloc(sizeof(Trie));
int i;
for (i = 0; i < ALPHABET_SIZE; i++)
{
newNode->children[i] = NULL;
}
newNode->isLeaf = false;
return newNode;
}
/** Inserts a word into the trie. */
void trieInsert(Trie *obj, char *word)
{
int index;
int length = strlen(word);
int i;
for (i = 0; i < length; i++)
{
index = word[i] - 'a';
if (!obj->children[index])
{
obj->children[index] = trieCreate();
}
obj = obj->children[index];
}
obj->isLeaf = true;
}
/** Returns if the word is in the trie. */
bool trieSearch(Trie *obj, char *word)
{
int index;
for (int i = 0; i < strlen(word); i++)
{
index = word[i] - 'a';
if (!obj->children[index])
{
return false;
}
obj = obj->children[index];
}
return (obj != NULL && obj->isLeaf);
}
/** Returns if there is any word in the trie that starts with the given prefix. */
bool trieStartsWith(Trie *obj, char *prefix)
{
int index;
int length = strlen(prefix);
int i;
for (i = 0; i < length; i++)
{
index = prefix[i] - 'a';
if (!obj->children[index])
{
return false;
}
obj = obj->children[index];
}
return true;
}
void trieFree(Trie *obj)
{
free(obj);
}
實作上有幾點要注意:
false
。isEndOfWord
,同時確認是否檢查完所有字元。isEndOfWord
Trie
可以當成是專門儲存 Strings
的可行方案,尤其需要 prefix search
的情況特別適合。