LeetCode 208. Implement Trie (Prefix Tree)

字典树。

测试中有:aaaaaaaaaaa... 的输入,如果每个节点用定长数组存储孩子的话,那就是26^len的空间复杂度(len为输入的长度),内存会不够的。

所以用map<char, TrieNode*>保存其孩子。


第三遍(将第二遍中search和startsWith的行为抽象成searchNode方法):

struct TrieNode
{
	map<char, shared_ptr<TrieNode>> children;
	bool is_word = false;
};

class Trie
{
public:
	Trie(): root(shared_ptr<TrieNode>(new TrieNode)) {}

	// Inserts a word into the trie.
	void insert(string word) const
	{
		if (word.empty())
		{
			return ;
		}
		auto node = root;
		for (size_t i = 0; i < word.size(); node = node->children[word[i ++]])
		{
			if (node->children.find((word[i])) == node->children.end())
			{
				node->children[word[i]] = shared_ptr<TrieNode>(new TrieNode);
			}
		}
		node->is_word = true;
	}

	// Returns if the word is in the trie.
	bool search(string word) const
	{
		auto node = searchNode(word);
		return node!=nullptr && node->is_word;
	}

	// Returns if there is any word in the trie
	// that starts with the given prefix.
	bool startsWith(string prefix) const
	{
		return searchNode(prefix) != nullptr;
	}

private:
	shared_ptr<TrieNode> searchNode(string word) const
	{
		auto node = root;
		for (size_t i = 0; i < word.size(); node = node->children[word[i ++]])
		{
			if (node->children.find(word[i]) == node->children.end())
			{
				return nullptr;
			}
		}
		return node;
	}

	shared_ptr<TrieNode> root;
};
第二遍(将第一次代码中的尾递归改成了迭代,速度从270ms提升到了200ms):

struct TrieNode
{
	map<char, shared_ptr<TrieNode>> children;
	bool is_word = false;
};

class Trie
{
public:
	Trie(): root(shared_ptr<TrieNode>(new TrieNode)) {}

	// Inserts a word into the trie.
	void insert(string word) const
	{
		if (word.empty())
		{
			return ;
		}
		auto node = root;
		for (size_t i = 0; i < word.size(); node = node->children[word[i ++]])
		{
			if (node->children.find((word[i])) == node->children.end())
			{
				node->children[word[i]] = shared_ptr<TrieNode>(new TrieNode);
			}
		}
		node->is_word = true;
	}

	// Returns if the word is in the trie.
	bool search(string word) const
	{
		// no special judge for empty word here
		auto node = root;
		for (size_t i = 0; i < word.size(); node = node->children[word[i ++]])
		{
			if (node->children.find(word[i]) == node->children.end())
			{
				return false;
			}
		}
		return node->is_word;
	}

	// Returns if there is any word in the trie
	// that starts with the given prefix.
	bool startsWith(string prefix) const
	{
		auto node = root;
		for (size_t i = 0; i < prefix.size(); node = node->children[prefix[i ++]])
		{
			if (node->children.find(prefix[i]) == node->children.end())
			{
				return false;
			}
		}
		return true;
	}

private:
	shared_ptr<TrieNode> root;
};

第一遍:

class TrieNode
{
public:
	// Initialize your data structure here.
	TrieNode()
	{
		is_word = false;
	}

	void insert(const string& word)
	{
		if (!word.empty())
		{
			nodes[word.front()] =
				nodes[word.front()] != nullptr ?
					nodes[word.front()] : new TrieNode();
			nodes[word.front()]->insert(word.substr(1));
		} else
		{
			is_word = true;
		}
	}

	bool search(string word)
	{
		if (!word.empty())
		{
			if (nodes[word.front()] == nullptr)
			{
				return false;
			} else
			{
				return nodes[word.front()]->search(word.substr(1));
			}
		}
		return is_word;
	}

	bool startsWith(string prefix)
	{
		if (!prefix.empty())
		{
			if (nodes[prefix.front()] == nullptr)
			{
				return false;
			} else
			{
				return nodes[prefix.front()]->startsWith(prefix.substr(1));
			}
		}
		return true;
	}

	// MLE!!!
	// TrieNode* nodes[26];
	map<char, TrieNode*> nodes;
	bool is_word;
};

class Trie
{
public:
	Trie()
	{
		root = new TrieNode();
	}

	// Inserts a word into the trie.
	void insert(string word)
	{
		root->insert(word);
	}

	// Returns if the word is in the trie.
	bool search(string word)
	{
		return root->search(word);
	}

	// Returns if there is any word in the trie
	// that starts with the given prefix.
	bool startsWith(string prefix)
	{
		return root->startsWith(prefix);
	}

private:
	TrieNode* root;
};


你可能感兴趣的:(LeetCode,数据结构,C++,trie,字典树)