这三个解决方案的时间复杂度是多少?

时间:2018-12-22 16:49:04

标签: python time-complexity

我有Leetcode问题的这三种解决方案,在这里并没有真正理解时间复杂度的差异。为什么最后一个函数的速度是第一个函数的两倍?

68毫秒
def numJewelsInStones(J, S):
    count=0
    for s in S:
        if s in J:
            count += 1
    return count
40毫秒
def numJewelsInStones(J, S):
    return sum(s in J for s in S)
32毫秒
def numJewelsInStones(J, S):
    return len([x for x in S if x in J])

3 个答案:

答案 0 :(得分:4)

  

为什么最后一个函数的速度是第一个函数的两倍?

以大O表示法表示的分析时间复杂度对于所有人来说都是相同的,但是服从常数。那是例如O(n)实际上是O(c*n)的意思,但是在比较时间复杂度时,约定会忽略c

每个函数都有一个不同的c。特别是

  • 循环通常比生成器慢
  • 生成器的
  • sum可能是用C代码执行的(求和部分,加上数字)
  • len是对数组的简单属性“单一操作”查找,可以在恒定时间内完成,而sum需要n的添加操作。

因此c(for) > c(sum) > c(len),其中c(f)是功能/声明f的假设固定开销度量。

您可以通过disassembling每个函数来检查我的假设。

除此之外,由于系统中正在运行其他进程,因此测量值可能会受到变化的影响。为了从您的分析中消除这些影响,请取每个函数至少1000次调用的平均执行时间(您可能会发现c小于此变化,尽管我并不希望如此)。

  

这些功能的时间复杂度是多少?

请注意,尽管所有函数都具有相同的大O时间复杂度,但是根据您用于J, S的数据类型,后者会有所不同。如果J, S的类型为:

  • dict,函数的复杂度将在O(n)
  • set,函数的复杂度将在O(n)
  • list,函数的复杂度将在O(n*m)中,其中n,m分别是J, S变量的大小。请注意,如果n ~ m会有效地变成O(n^2)。换句话说,请勿使用list

为什么数据类型很重要?因为Python的in运算符实际上只是为特定类型实现的成员资格测试的代理。具体来说,dictset成员资格测试在恒定时间的O(1)中工作,而list的成员资格测试在O(n)时间中工作。因为在list情况下J的每个成员都有S的每个成员通过,反之亦然,所以总时间在O(n*m)中。有关详情,请参见Python's TimeComplexity wiki

答案 1 :(得分:3)

大的O符号表示时间复杂度,它说明解决方案如何随着输入集的增长而增长。换句话说,它们如何相对相关。如果您的解决方案是O(n),则随着输入的增长,完成时间线性增长。更具体地说,如果解决方案为O(n),并且当数据集为100时需要10秒,那么当数据集为1000时应该大约需要100秒。

您的第一个解决方案是O(n),我们知道这是因为S中的for循环,因为for循环了整个数据集一次。如果J中的s假设J是一个集合或字典可能是恒定时间O(1),则其背后的原因有点超出了问题的范围。结果,总的来说第一个解是线性时间O(n)。

如果您对多个数据集进行测试并随时间进行平均,则其他解决方案之间的细微差别很可能可以忽略不计,其中要考虑启动时间和影响测试结果的其他因素。此外,Big O表示法会丢弃系数,因此,例如O(3n)〜= O(n)。

您会在所有其他解决方案中注意到您具有相同的概念,遍历整个集合并检查集合或字典中是否存在。结果,所有这些解都是O(n)。时间的差异可以归因于同时运行的其他进程,所使用的某些内置函数是纯C事实,也归因于测试不足所致的差异。

答案 2 :(得分:0)

第二个函数比第一个更快,因为使用了generator而不是loop。第三个函数比第二个函数快,因为第二个求和生成器输出(返回类似于list的东西),但是第三个函数-仅计算其长度。