锁定长度,逐一遍历法
class Solution(object):
def findAllConcatenatedWordsInADict(self, words):
"""
:type words: List[str]
:rtype: List[str]
"""
words = sorted(words,key=lambda i:len(i)) #将单词按照长度排序
s = set(words) #放入集合中,可以去重
ans = []
while words:
word = words.pop(-1) #从长度最长的元素开始逐一取出
s.remove(word) #从集合中去除该单词,因为是从最长的单词开始判断,所以不会存在短单词是由长单词组成的情况。
L = len(word)
stack = [0]
while stack:
p = stack.pop(0) #取出栈中第一项
flag = False
for i in range(p+1,L+1):#限制字符长度不可超过取出的单词长度会产生溢出
if word[p:i] in s: #遍历不同长度的单词是否存在在集合中
stack.append(i) #将下一个单词判断的开始位置放入栈中
if i == L: #如果取完存在单词后右侧下标恰好为所判断单词总长度那么就代表该单词是一个连接词
ans.append(word)
flag = True #找到一个连接词,跳出两层循环,继续判断下一个词
break
if flag:
break
return ans
建立前缀树进行单词前缀逐一比对的方法
class Solution(object):
def findAllConcatenatedWordsInADict(self, words):
"""
:type words: List[str]
:rtype: List[str]
"""
def check_word(word,pre_dict):
if len(word) == 0: #因为是递归调用,用于结束递归,结束的条件是单词正好是连接词,然后从单词长度加一的位置调用函数自身时,传入的字符串为None,所以长度为0,仅有这一种情况会使得单词长度变为0
return True
cur_dict = pre_dict
for index,c in enumerate(word):
cur_dict = cur_dict.get(c,None) #取字母元素,取不到的话默认返回None
if cur_dict is None: #没有与当前所取字母元素对应的字典树,即匹配失败
return False
if cur_dict.get("end",0) == 1:#如果取到的是结束符那么代表当前存在单词匹配结束,有可能为连接词,继续向后判断是否为已经存在的单词
if check_word(word[index+1:],pre_dict):# 递归调用函数判断发现单词的下一个位置到单词结束
return True
return False
words.sort(key = lambda x:len(x)) #单词按长度排列 [u'cat', u'dog', u'rat', u'cats', u'dogcatsdog', u'catsdogcats', u'ratcatdogcat', u'hippopotamuses']
ans = list()
pre_dict = dict() #前缀字典
for item in words: #遍历单词,此处有讲究,从短的开始进行比对,首先建立短单词的前缀树,用于组成长单词,不会存在短单词由长单词组成的情况。
if len(item) == 0:
continue
if check_word(item,pre_dict):#检查是否为连接词
ans.append(item)
else:
cur_dict = pre_dict
for c in item:
if cur_dict.get(c,None) is None:#检查是否存在前缀树
cur_dict[c] = dict() #建立键值并添加新的子字典
cur_dict = cur_dict.get(c) #转移跟踪指针到子字典树中,用于添加下一个元素到字典树中
cur_dict["end"] = 1 #添加单词结尾标志
return ans