题目描述
分析
最朴素的思想是通过枚举字典中的每个单词,判断其是否在s中出现过,然后选择长度最大且字典序最小的单词返回
代码一
def findLongestWord(self, s: str, dictionary: list[str]) -> str:
res = ""
for t in dictionary:
i = j = 0
while i < len(t) and j < len(s):
if t[i] == s[j]:
i += 1
j += 1
if i == len(t):
if len(t) > len(res) or (len(t) == len(res) and t < res):
res = t
return res
分析代码一可以发现,需要枚举所有的单词才能确定结果,如果事先对字典中的单词按照长度降序排列,字典序升序排列,那么第一个出现在s中的单词就是最终的结果
代码二
def findLongestWord(self, s: str, dictionary: list[str]) -> str:
# 对字典按照长度降序,字典序升序排列,原地排序
dictionary.sort(key=lambda x:(-len(x), x))
for d in dictionary:
i = j = 0
while i < len(s) and j < len(d):
if s[i] == d[j]:
j += 1
i += 1
if j == len(d):
return d
return ""
分析代码二可以发现,耗时操作主要用于寻找下一个匹配字符,如果能在o(1)时间内找到从当前为止开始的下一个匹配字符的为止,则可以大大降低检索的时间,假设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示s中从位置i开始字符j第一次出现的位置则有下面的状态转移方程:
代码三
def findLongestWord(self, s: str, dictionary) -> str:
# 初始化dp矩阵,这种初始化存在问题,dp每个列表都指向相同的地址,修改其中一个会改变其他的列表元素
# dp = [[-1] * 26] * len(s)
dp = []
for i in range(0, len(s)):
dp.append([-1] * 26)
# 从过后往前填充矩阵 ord是获取字符的ASCII码,chr是获取对应ASCII码的字符
dp[len(s) - 1][ord(s[len(s) - 1]) - ord('a')] = len(s) - 1
for i in range(len(s) - 2, -1, -1):
for j in range(25, -1, -1):
if s[i] == chr(j + ord('a')):
dp[i][j] = i
else:
dp[i][j] = dp[i + 1][j]
# 对字典进行排序
dictionary.sort(key=lambda x:(-len(x), x))
for d in dictionary:
i = j = 0
while i < len(d) and j < len(s):
# 查找字符d[i]从为止j开始是否出现过
if dp[j][ord(d[i]) - ord('a')] == -1:
break
j = dp[j][ord(d[i]) - ord('a')] + 1
i += 1
if i == len(d):
return d
return ""