LeetCode 208. Implement Trie (Prefix Tree)

本文详细探讨了如何优化字典树结构,以高效存储和搜索长字符串,通过使用map容器替代定长数组来节省内存,同时改进了搜索和前缀匹配行为的实现方式,显著提升了性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

字典树。

测试中有: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;
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值