This is a variation (perhaps improvement) of my earlier answer. Here, we can construct the tree and then obtain relevant tree information via its various methods. The output from running it is shown at the end.
"""
A module that implements trie search tree.
"""
from __future__ import print_function
from collections import defaultdict
import doctest
class TrieNode:
"""
Node of a trie search tree.
Contains as children other trie nodes.
Each node contains a single character as key.
Ref: https://en.wikipedia.org/wiki/Trie
"""
def __init__(self):
"""
Initialize with empty children.
"""
self.is_end = False
self.children = defaultdict(TrieNode)
self.count = 0 # reached how many times
self.depth = 0 # reached by how long sub-string
def add_nodes(self, word):
"""
Add child nodes recursively.
First character of input word will be added as a direct child.
The next character will be a child of the child, and so on.
Args:
word (str): Input word to process.
"""
if not word:
return
node = self
for char in word:
node = node.children[char]
node.is_end = True
node.count += 1
node.depth = len(word)
def make_tree(self, words):
"""
Make a complete trie tree from the list of input words.
"""
for word in words:
self.add_nodes(word)
def total_length(self):
"""
Return the total length of node and children.
Returns:
length (int): Zero for an empty tree.
Positive integer otherwise.
"""
length = 0
for child in self.children.values():
length += child.total_length()
if self.is_end:
length += self.count * self.depth
return length
def num_words(self, uniq=False):
"""
Get the number of words.
A word is represented by its endpoint. Multiple occurences are counted
multiple times, unless uniq argument is set to True.
Args:
uniq (bool): If True, counts only unique word occurences.
Returns:
cnt (int): Zero for an empty tree.
Positive integer otherwise.
"""
cnt = 0
for child in self.children.values():
cnt += child.num_words(uniq)
if self.is_end:
if uniq:
cnt += 1
else:
cnt += self.count
return cnt
def max_depth(self):
"""
Get the maximum depth.
Returns:
depth (int): Zero for an empty tree.
Positive integer otherwise.
"""
depth = 0
for child in self.children.values():
depth = max(depth, child.max_depth())
if self.is_end:
return self.depth
else:
return depth
def word_freq(self, prefix=''):
"""
Get the words and number of occurences.
Returns:
wfreq (dict): Keys are words, values are number of occurences.
"""
wfreq = {}
for char, child in self.children.items():
wfreq.update(child.word_freq(prefix+char))
if self.is_end and prefix:
wfreq[prefix] = self.count
return wfreq
def tree_info(self):
"""
Get relevant info on the current tree.
Returns:
info (dict): Information about the tree.
"""
info = {
'total_length' : self.total_length(),
'num_words' : self.num_words(),
'num_uniq_words' : self.num_words(uniq=True),
'max_depth' : self.max_depth(),
'word_freq' : self.word_freq()
}
return info
if __name__ == "__main__":
test_strs = ["abcabcabb", "catcatcatcat", "aaaaaa", "aaaaaba"]
for ts in test_strs:
print("Input: {:s}".format(ts))
trees = []
# Create all possible trees
factors = (x for x in range(1, len(ts)) if not len(ts)%x)
for sublen in factors:
# Make the trie tree
subwords = (ts[x:x+sublen] for x in range(0, len(ts), sublen))
root = TrieNode()
root.make_tree(subwords)
trees.append(root)
# Find length of shortest whole repetitive substring
depths = [len(ts)]
depths += (tree.max_depth() for tree in trees if tree.num_words(uniq=True) == 1)
print(" Length of shortest whole repetitive substring: {:d}".format(min(depths)))
# Print each tree's info
for tree in trees:
print(" Tree info: {}".format(tree.tree_info()))
Here's the output:
Input: abcabcabb
Length of shortest whole repetitive substring: 9
Tree info: {'word_freq': {'c': 2, 'b': 4, 'a': 3}, 'total_length': 9, 'max_depth': 1, 'num_words': 9, 'num_uniq_words': 3}
Tree info: {'word_freq': {'abb': 1, 'abc': 2}, 'total_length': 9, 'max_depth': 3, 'num_words': 3, 'num_uniq_words': 2}
Input: catcatcatcat
Length of shortest whole repetitive substring: 3
Tree info: {'num_words': 12, 'word_freq': {'c': 4, 't': 4, 'a': 4}, 'max_depth': 1, 'num_uniq_words': 3, 'total_length': 12}
Tree info: {'num_words': 6, 'word_freq': {'ca': 2, 'at': 2, 'tc': 2}, 'max_depth': 2, 'num_uniq_words': 3, 'total_length': 12}
Tree info: {'num_words': 4, 'word_freq': {'cat': 4}, 'max_depth': 3, 'num_uniq_words': 1, 'total_length': 12}
Tree info: {'num_words': 3, 'word_freq': {'catc': 1, 'tcat': 1, 'atca': 1}, 'max_depth': 4, 'num_uniq_words': 3, 'total_length': 12}
Tree info: {'num_words': 2, 'word_freq': {'catcat': 2}, 'max_depth': 6, 'num_uniq_words': 1, 'total_length': 12}
Input: aaaaaa
Length of shortest whole repetitive substring: 1
Tree info: {'num_words': 6, 'word_freq': {'a': 6}, 'max_depth': 1, 'num_uniq_words': 1, 'total_length': 6}
Tree info: {'num_words': 3, 'word_freq': {'aa': 3}, 'max_depth': 2, 'num_uniq_words': 1, 'total_length': 6}
Tree info: {'num_words': 2, 'word_freq': {'aaa': 2}, 'max_depth': 3, 'num_uniq_words': 1, 'total_length': 6}
Input: aaaaaba
Length of shortest whole repetitive substring: 7
Tree info: {'num_words': 7, 'word_freq': {'a': 6, 'b': 1}, 'max_depth': 1, 'num_uniq_words': 2, 'total_length': 7}
n.times do |i|
(RTFM?) the identifier list between bars receives value tuples from the iterator before thedo
.) \$\endgroup\$how [the referred post] is related to RobAu's work? It is totally different.
Right.If I read your points wrong
At least one of us is confused as to what this post is about, which is the one I commented. \$\endgroup\$