\$\begingroup\$
\$\endgroup\$
3
https://leetcode.com/problems/implement-trie-prefix-tree/
Please comment about performance and style.
Implement a trie with insert, search, and startsWith 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.
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace TrieQuestions
{
/// <summary>
/// https://leetcode.com/problems/implement-trie-prefix-tree/
/// </summary>
[TestClass]
public class TrieTreeImplementation
{
[TestMethod]
public void TrieInsertTest()
{
Trie trie = new Trie();
trie.Insert("cat");
Assert.IsTrue(trie.Search("cat"));
}
[TestMethod]
public void TriePrefixSearchTest()
{
Trie trie = new Trie();
trie.Insert("cats");
Assert.IsTrue(trie.StartsWith("cat"));
}
[TestMethod]
public void OneLetterEdgeCaseTest()
{
Trie trie = new Trie();
trie.Insert("a");
Assert.IsTrue(trie.Search("a"));
Assert.IsTrue(trie.StartsWith("a"));
}
}
public class Trie
{
public TrieNode Head { get; set; }
/** Initialize your data structure here. */
public Trie()
{
Head = new TrieNode();
}
/** Inserts a word into the trie. */
public void Insert(string word)
{
var current = Head;
for (int i = 0; i < word.Length; i++)
{
if (!current.Edges.ContainsKey(word[i]))
{
current.Edges.Add(word[i], new TrieNode());
}
current = current.Edges[word[i]];
}
current.IsTerminal = true;
}
/** Returns if the word is in the trie. */
public bool Search(string word)
{
var current = Head;
for (int i = 0; i < word.Length; i++)
{
if (!current.Edges.ContainsKey(word[i]))
{
return false;
}
current = current.Edges[word[i]];
}
return current.IsTerminal == true;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
public bool StartsWith(string prefix)
{
var current = Head;
for (int i = 0; i < prefix.Length; i++)
{
if (!current.Edges.ContainsKey(prefix[i]))
{
return false;
}
current = current.Edges[prefix[i]];
}
return true;
}
}
public class TrieNode
{
public Dictionary<char, TrieNode> Edges { get; set; }
public bool IsTerminal { get; set; }
public TrieNode()
{
Edges = new Dictionary<char, TrieNode>();
}
}
}
asked May 17, 2019 at 20:56
-
\$\begingroup\$ @wolfy no you can't. Why is it better? Maybe I can create a singleton or something close to it. \$\endgroup\$Gilad– Gilad2019年05月17日 21:55:55 +00:00Commented May 17, 2019 at 21:55
-
\$\begingroup\$ @Wolfy: C# is a managed language, so I'm not sure what you're getting at? \$\endgroup\$Pieter Witvoet– Pieter Witvoet2019年05月17日 23:33:49 +00:00Commented May 17, 2019 at 23:33
-
\$\begingroup\$ @PieterWitvoet ahh okay then nevermind, sorry I never used C# before... \$\endgroup\$Wolfy– Wolfy2019年05月17日 23:35:09 +00:00Commented May 17, 2019 at 23:35
1 Answer 1
\$\begingroup\$
\$\endgroup\$
0
In terms of data structures and algorithms this all looks pretty straightforward - not much to say about that.
Performance
Edges.ContainsKey
andEdges[...]
each perform a lookup.Edges.TryGetValue
lets you achieve the same with just a single lookup.
Design
- I see no reason why
Trie.Head
should be public, and certainly not why it should have a public setter. That's poor encapsulation. Likewise,TrieNode.Edges
should be get-only: you don't want outside code to be able to doEdges = null;
. Search
andStartsWith
do exactly the same thing, except for the final check. I'd move the duplicate code to aTrieNode FindNode(string prefix)
helper method.TrieNode
is only used internally withinTrie
, so it makes sense to make it a private inner class.
Other notes
- You can remove
Trie
's constructor if you initializeHead
directly:TrieNode Head { get; } = new TrieNode();
. The same goes forTrieNode
andEdges
. - I'd replace those
for
loops withforeach
loops, for clarity's sake. - Comparing a boolean against
true
is unnecessary. Just doreturn current.IsTerminal;
- I'd replace those default LeetCode comments with C#-specific xml comments.
answered May 18, 2019 at 1:03
lang-cs