你能每个词只用一次吗?例如,如果您有 de 和 dede,那么 (de, de) 是一个答案吗?为了简单起见,我只是假设每个单词出现一次,你有很多单词但没有记忆限制。
1- 构建一个自定义树,使得每个节点如下所示:
class node():
is_there_a_word_that_ends_here = T/F
children = dict() # other nodes, key is the letter of the node
例如,如果您有三个单词,例如 ["ab", "abc", "ade", "c"],那么您将有一个如下所示的树(如果 is_there_a_word_that_ends_here 节点的值为 true,则我放一个 * 号)
head ---a---b*---c*
| |
| L-d----e*
|
L--c*
2-根据长度对单词进行分组。从长度最小的单词开始,因为当您接触到较大的单词时,您想知道较小单词的“细分”。在这里,您可以使用add_word_to_result 可以(应该)缓存结果的函数递归地执行此操作。
results = dict() # keys: possible words you can reach, values: ways to reach them
for word in words_in_ascending_length:
add_word_to_result(word, tree, results)
和add_word_to_result 将开始在树中移动。如果它在一个节点中看到is_there_a_word_that_ends_here,它会调用add_word_to_result(remaining_part_of_the_word, tree, results)。例如,如果您有“abc”,那么您会在“ab”中看到 *,然后调用 add_word_to_result("c", tree, results)。
实现递归函数是问题的“有趣部分”(也是更耗时的部分),所以我把它留给你。此外,作为奖励,您可以想办法以一种有效的方式避免将重复项添加到结果中(因为在某些情况下会发生重复项)。
(编辑:也许您需要缓存现有单词和不存在单词的细分 - 例如单词结尾的细分 - 以便在返回结果之前不必将它们分开,如果这句话使任何意义)
我希望这会有所帮助。
奖励:示例代码(还没有真正测试过,但应该可以工作,并且您可以做出重大改进,但我现在懒得做。您可以稍微更改结构以将 results 传递给 add_word_to_result , 这样您就可以记住迄今为止所有可能的组合,因此您只需使用它而不是 add_word_to_result(head, head, words_left[1:], combinations, words_passed+words_left[0]+","),而不要进行不必要的递归)
words = ["leetcode", "leet", "code", "le", "et", "etcode", "de", "decode", "deet"]
class node():
def __init__(self, letter, is_there_a_word_that_ends_here):
self.letter = letter # not really used but it feels weird to not have it in class
self.is_there_a_word_that_ends_here = is_there_a_word_that_ends_here
self.children = dict()
# actually defining tree is redundant you can just merge tree and node class together, but maybe this is more explicit
class Tree():
def __init__(self):
self.head = node(None, False)
def add(self, word, head=None):
if head is None:
head=self.head
if word[0] not in head.children.keys():
head.children[word[0]] = node(word[0], False)
if len(word) == 1:
head.children[word[0]].is_there_a_word_that_ends_here = True
else:
self.add(word[1:], head=head.children[word[0]])
words = sorted(words, key=lambda w: len(w))
results = dict()
tree = Tree()
for word in words:
tree.add(word)
def add_word_to_result(head, current_node, words_left, combinations, words_passed):
if words_left[0] in current_node.children.keys():
# this does not have to happen because we call this function with words that are not in the list as well
next_node = current_node.children[words_left[0]]
if len(words_left) == 1 and next_node.is_there_a_word_that_ends_here:
combinations.append(words_passed+words_left)
elif next_node.is_there_a_word_that_ends_here:
add_word_to_result(head, head, words_left[1:], combinations, words_passed+words_left[0]+",")
add_word_to_result(head, next_node, words_left[1:], combinations, words_passed + words_left[0])
else:
add_word_to_result(head, next_node, words_left[1:], combinations, words_passed+words_left[0])
for word in words:
results[word] = []
add_word_to_result(tree.head, tree.head, word, results[word], "")
print(results)
# {'le': ['le'], 'et': ['et'], 'de': ['de'], 'leet': ['le,et', 'leet'], 'code': ['code'], 'deet': ['de,et', 'deet'], 'etcode': ['et,code', 'etcode'], 'decode': ['de,code', 'decode'], 'leetcode': ['le,et,code', 'le,etcode', 'leet,code', 'leetcode']}