以下是此问题的代码。我正在使用Trie树来解决这个问题,并想知道在更好的时间复杂性或空间复杂性方面是否还有其他更好的想法。此外,任何错误和代码风格的建议都很受欢迎。
问题:
给定一组字符串,返回给定输入字集的最小子集---包含给定输入字集中每个输入字的前缀。前缀应该是给定输入集中的完整输入字,而不是给定单词的前缀。对于没有前缀的单词, 回归自己。
如果列表是[' foo',' foog',' food',' asdf']返回[' foo',' asdf']
返回foo
,因为foo
是foo
(本身)的前缀,foog
的前缀和food
的前缀(换句话说,{ {1}}可以代表"更长的字符串,如foo
和foog
)。输出还包含food
,因为它不是输入列表中任何其他单词的前缀,因此输出本身。
空集不是正确的答案,因为它不包含最长的前缀。
源代码:
asdf
答案 0 :(得分:1)
我认为这个问题是明确无误的。 (也许在编辑之前它更难)。答案是,特里似乎完全正确。
从输入单词构建trie,然后首先遍历深度。每次找到输入集中的节点(内部节点或叶子)时,将该节点上的单词添加到输出中并停止搜索它的子节点。
答案 1 :(得分:1)
我更喜欢简单的while
- 循环方法,在开头有一个排序:
minimal = []
words = ['foo', 'foog', 'food', 'asdf']
words.sort(key=lambda x: (len(x), x))
while words:
word = words[0]
minimal.append(word)
words = [ x for x in words[1:] if not x.startswith(word) ]
print minimal
当没有字符串是任何其他字符串的前缀时,这是一个在最差的O(n ** 2)运行的相当有效的实现。
后记#1:你可以通过排序单词的长度而不是长度和字母顺序来使排序略微提高效率。例如,改变这一行:
words.sort(key=lambda x: (len(x), x))
为:
words.sort(key=lambda x: len(x))
当然排序是O(n(log n)),它是运行时/复杂性的下限。
后记#2:
如果您更喜欢已定义的内存特性,则可以在words
列表中使用标记而不是过滤。此算法的标记版本如下所示:
words = [ 'foo', 'foog', 'food', 'asdf' ]
words.sort(key=lambda x: len(x))
marked = [ False for _ in words ]
for i in range(0, len(words)):
is_marked = marked[i]
if is_marked: continue
word = words[i]
for j in range(i + 1, len(words)):
if not marked[j] and words[j].startswith(word):
marked[j] = True
minimal = [ word for word, is_marked in zip(words, marked) if not is_marked ]
它比我首选的过滤版本稍微冗长,但有一个好处,就是不能在循环的每个连续传递中不断地创建/销毁单词数组。