我正在学习一些python,在此过程中,我正在从codewars做一些简单的katas。 我遇到了https://www.codewars.com/kata/scramblies问题。
我的解决方法如下:
def scramble(s1,s2):
result = True
for character in s2:
if character not in s1:
return False
i = s1.index(character)
s1 = s1[0:i] + s1[i+1:]
return result
虽然结果正确,但速度不够快。我的解决方案在12000毫秒后超时。 我查看了其他人提出的解决方案,其中涉及一套解决方案。
def scramble(s1,s2):
for letter in set(s2):
if s1.count(letter) < s2.count(letter):
return False
return True
为什么我的解决方案比另一种慢得多?除非我误解了切片字符串的效率,否则它看起来应该不是。我解决这个问题的方法是否有缺陷或不是pythonic?
答案 0 :(得分:1)
对于这种限制程序运行时间的在线编程挑战,测试输入将包含一些相当大的示例,并且通常设置时间限制,这样您就不必再压缩最后一毫秒的性能了。代码之外,但是您必须编写足够低的computational complexity算法。要回答您的算法超时的原因,我们可以使用big O notation对其进行分析以找到其计算复杂性。
首先,我们可以使用复杂性来标记每个单独的语句,其中n
是s1
的长度,而m
是s2
的长度:
def scramble(s1,s2):
result = True # O(1)
for character in s2: # loop runs O(m) times
if character not in s1: # O(n) to search characters in s1
return False # O(1)
i = s1.index(character) # O(n) to search characters in s1
s1 = s1[0:i] + s1[i+1:] # O(n) to build a new string
return result # O(1)
则总复杂度为O(1 + m *(n +1 + n + n)+1)或更简单地为O(m * n)。对于这个问题,这不是很有效。
为什么备用算法更快的关键在于set(s2)
仅包含字符串s2
中的不同字符。这很重要,因为构成这些字符串的字母的大小恒定且有限;小写字母大概为26。鉴于此,替代算法的外循环实际上最多运行26次:
def scramble(s1,s2):
for letter in set(s2): # O(m) to build a set
# loop runs O(1) times
if s1.count(letter) < s2.count(letter): # O(n) + O(m) to count
# chars from s1 and s2
return False # O(1)
return True # O(1)
这意味着备用算法的复杂度为O(m + 1 *(n + m + 1)+1)或更简单地为O(m + n),这意味着它比您的算法效率更高。
答案 1 :(得分:0)
首先,set
快速且非常擅长于其工作。对于in
之类的事物,set
比list
更快。
第二,您的解决方案比正确的解决方案要做的工作更多。请注意,第二个解决方案是如何从未修改过s1
或s2
的,而您的解决方案都占用了s1
的两个切片,然后重新分配了s1
。这以及调用.index()
。切片并不是最快的操作,主要是因为必须分配内存并且必须复制数据。 .remove()
可能比.index()
和切片的组合要快。
这里的基本信息是,如果任务可以用更少的操作完成,那么显然它将更快地执行。切片也比大多数其他方法昂贵,因为与正确解决方案使用的.count()
之类的计算方法相比,分配空间和复制内存是更昂贵的操作。