hackerrank“制作字谜”挑战超时失败
Posted
技术标签:
【中文标题】hackerrank“制作字谜”挑战超时失败【英文标题】:Timeout failure on hackerrank "Making Anagram" challenge 【发布时间】:2018-03-16 05:06:54 【问题描述】:堆栈上的第一个问题, 我在hackerrank的前几个挑战中遇到了“多少删除来分析2个单词”。我在网上看到了其他一些解决方案,但我不明白为什么我的速度慢得多。我似乎有一个“正确”的算法,因为我计算了一些测试用例并找到了相应的预期输出
def number_needed(a, b):
count = 0
isFound = False
matchedBs = []
for letterA in a:
for j,letterB in enumerate(b):
if letterA == letterB and (j not in matchedBs):
isFound = True
matchedBs.append(j)
break
if not isFound:
count += 1
isFound = False
return count + (len(b)-len(matchedBs))
a = input().strip()
b = input().strip()
print(number_needed(a, b))
所以我想弄清楚我的算法的总体思路是瓶颈还是其中的一些错误。 谢谢!
【问题讨论】:
每个字母是否只出现一次?因为matchedBs每个字母只有一次。 @BradSolomon 失败的测试用例使用 400-500 个字符字符串 @inarilo 没有一个字母可以出现多次,但我不确定为什么会出现问题。 我不知道python所以也许我弄错了,但你似乎忽略了任何已经在matchedBs中的字母,所以任何重复的字母都不会被计算在内,你似乎也不会检查重复的字母是否匹配 B 中的重复字母,而不是已经匹配的相同出现.. if 语句的第二部分检查是否存在? "letterA == letterB and (j not in mappedBs)" 【参考方案1】:你可以在这里使用line profiling。你可以使用conda install line_profiler
。
首先将您的函数合并到一个脚本中,并用@profile
装饰它。这是那个脚本:
# number_needed.py
from string import ascii_letters
import numpy as np
@profile
def number_needed(a, b):
count = 0
isFound = False
matchedBs = []
for letterA in a:
for j,letterB in enumerate(b):
if letterA == letterB and (j not in matchedBs):
isFound = True
matchedBs.append(j)
break
if not isFound:
count += 1
isFound = False
return count + (len(b)-len(matchedBs))
np.random.seed(123)
s1 = ''.join(np.random.choice(list(ascii_letters), size=500).tolist())
s2 = ''.join(np.random.choice(list(ascii_letters), size=500).tolist())
def main():
return number_needed(s1, s2)
if __name__ == '__main__':
main()
然后在 IPython/JupyterQt 中调用下面的命令。您可能需要根据您所在目录的外观更改路径:
%run C:/Users/YOURNAME/Anaconda3/pkgs/line_profiler-2.0-py36_0/Lib/site-packages/kernprof.py -l -v number_needed.py
结果会逐行显示一些有用的统计信息。
Line # Hits Time Per Hit % Time Line Contents
==============================================================
5 @profile
6 def number_needed(a, b):
7 1 5 5.0 0.0 count = 0
8 1 3 3.0 0.0 isFound = False
9 1 2 2.0 0.0 matchedBs = []
10
11 501 468 0.9 0.2 for letterA in a:
12 136321 133965 1.0 46.4 for j,letterB in enumerate(b):
13 136229 151929 1.1 52.6 if letterA == letterB and (j not in matchedBs):
14 408 371 0.9 0.1 isFound = True
15 408 585 1.4 0.2 matchedBs.append(j)
16 408 425 1.0 0.1 break
17 500 472 0.9 0.2 if not isFound:
18 92 105 1.1 0.0 count += 1
19 500 459 0.9 0.2 isFound = False
20
21 1 5 5.0 0.0 return count + (len(b)-len(matchedBs))
看起来for j,letterB in enumerate(b):
被嵌套是你的罪魁祸首。您正在评估 136,000 次以下的行。也就是说,您在循环中运行的操作每次点击所花费的时间一样长,但它们几乎从未被评估过,因此作为一个整体,它们不会占用您的时间。 p>
不过,运行时似乎还不错。 s1
和 s2
在我的机器上为 14.7 毫秒。
【讨论】:
【参考方案2】:您的代码具有 O(n3) 复杂度(n 是 a
和 b
的长度):您循环 a
中的每个字符,将它们与 @987654325 中的每个字符进行比较@,然后检查该索引是否在已经匹配的字符列表中,这也是线性复杂度。
作为一种快速修复,您可以将matchedBs
设为set
,从而将复杂度降低到 O(n²)。但你可以做得更好:只需计算 a
和 b
中的所有单个字符。不要为此使用str.count
,否则您将再次获得O(n²);相反,使用dict
将字符映射到它们的计数,循环a
和b
一次,并相应地更新这些计数。最后,只需将 a
和 b
的计数差相加即可。
或者,使用 Python 的库,您可以为 a
和 b
创建两个 collections.Counter
并进行比较。
【讨论】:
以上是关于hackerrank“制作字谜”挑战超时失败的主要内容,如果未能解决你的问题,请参考以下文章
Python Hackerrank挑战给出了〜stdout没有响应〜错误
[不使用TOP的SELECT SSMS的最后一行Hackerrank挑战者