Trie Variation for a Hard Leetcode Problem
Here is the problem: Number of Distinct Substrings in a String - LeetCode
Given a string s, return the number of distinct substrings of s.
A substring of a string is obtained by deleting any number of characters (possibly zero) from the front of the string and any number (possibly zero) from the back of the string.
Example 1:
Input: s = "aabbaba" Output: 21 Explanation: The set of distinct strings is ["a","b","aa","bb","ab","ba","aab","abb","bba","aba","aabb","abba","bbab","baba","aabba","abbab","bbaba","aabbab","abbaba","aabbaba"]
Example 2:
Input: s = "abcdefg" Output: 28
Constraints:
1 <= s.length <= 500sconsists of lowercase English letters.
My first several attempts resulted in TLE. Approach was simple: N^2 nested loops, get the substring, compare with a hashtable. But the "get the substring" is actually expensive, and even the hash was expensive resulting in a runtime >> N^2.
When I went thru the discussions list, I noticed everyone mentioning "Tries". The variation I came up with worked quite well: every time that you try to add a character, return the Trie node for that character. That way, this operation will always be constant time. Always. And you end up with a truly N^2-time complexity. Since N=500, this results in 250K iterations, which is very fast. Code is down below, and Merry Christmas! ACC.
public class Solution
{
public int CountDistinct(string s)
{
if (String.IsNullOrEmpty(s)) return 0;
int retVal = 0;
Trie trie = new Trie();
Trie anchor = trie;
for (int i = 0; i < s.Length; i++)
{
trie = anchor;
for (int j = i; j < s.Length; j++)
{
bool isWord = false;
trie = trie.Add(s[j], ref isWord);
if (!isWord) retVal++;
}
}
return retVal;
}
}
public class Trie
{
private Hashtable nodes = null;
public Trie()
{
nodes = new Hashtable();
}
public Trie Add(char c, ref bool isWord)
{
if (!nodes.ContainsKey(c))
{
isWord = false;
Trie trie = new Trie();
nodes.Add(c, trie);
return trie;
}
else
{
isWord = true;
return (Trie)nodes[c];
}
}
}
Comments
Post a Comment