Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 排序数组的平方,为什么Sorted()方法比O(n)方法快?_Python_Algorithm_Time Complexity - Fatal编程技术网

Python 排序数组的平方,为什么Sorted()方法比O(n)方法快?

Python 排序数组的平方,为什么Sorted()方法比O(n)方法快?,python,algorithm,time-complexity,Python,Algorithm,Time Complexity,我正在研究leetcode算法问题 为什么使用内置排序方法的提交比下面的o(n)遍历方法更快 输入是一个带有整数的排序(非降序)列表 样本208 ms提交: class Solution: def sortedSquares(self, A: List[int]) -> List[int]: return sorted(x*x for x in A) class Solution: def sortedSquares(self, A: List[int])

我正在研究leetcode算法问题

为什么使用内置排序方法的提交比下面的o(n)遍历方法更快

输入是一个带有整数的排序(非降序)列表

样本208 ms提交:

class Solution:
    def sortedSquares(self, A: List[int]) -> List[int]:
        return sorted(x*x for x in A)
class Solution:
    def sortedSquares(self, A: List[int]) -> List[int]:
        start = 0
        end = len(A)-1

        B = []

        while start <= end:
            if abs(A[start]) >= abs(A[end]):
                B.append(A[start] * A[start])
                start += 1
            else:
                B.append(A[end] * A[end])
                end -= 1
        B.reverse()
        return B
我的意见书:

class Solution:
    def sortedSquares(self, A: List[int]) -> List[int]:
        return sorted(x*x for x in A)
class Solution:
    def sortedSquares(self, A: List[int]) -> List[int]:
        start = 0
        end = len(A)-1

        B = []

        while start <= end:
            if abs(A[start]) >= abs(A[end]):
                B.append(A[start] * A[start])
                start += 1
            else:
                B.append(A[end] * A[end])
                end -= 1
        B.reverse()
        return B
类解决方案:
def sortedSquares(self,A:List[int])->List[int]:
开始=0
结束=透镜(A)-1
B=[]
当开始=abs(A[结束])时:
附加(A[start]*A[start])
开始+=1
其他:
追加(A[end]*A[end])
结束-=1
B.反向()
返回B

仅仅因为您的算法具有更好的最坏情况运行时间,并不意味着它在实践中会更好。Python的内置排序方法经过了高度优化,因此对于相对较小的
c
,它的运行时间可以是
cnlg(n)
,而对于
dn
,您的算法虽然是
O(n)
,但可能有一个非常高的常量
d
。我们不知道您的输入是什么,因此它可能是一个由10000个元素组成的数组,
d
仍然显著大于
clg(10000)


另外,由于您的输入列表是排序的(非负部分),在这种情况下,可能会对几乎排序的列表进行一些优化(不确定,从来没有看过Python的排序实现)。

您可以对所有内容进行预平方(因此不需要
abs()
,特别是不需要对单个元素重复调用
abs()
):

C=[x*x代表A中的x]
开始=0
结束=透镜(A)-1
B=[]
当开始=C[结束]时:
B.追加(C[开始])
开始+=1
其他:
B.追加(C[结束])
结束-=1
B.反向()
返回B

但我没有测量它。例如,就地预平方可能执行得更好。

这是因为Python使用了一种基于marge_排序和insertion_排序的自适应排序算法。时间复杂度是

O(非登录)

用于python中的Sorted()


这就是为什么Sorted()的工作速度比您的更快的原因

Python内置的
Sorted
函数在本例中也是O(n)!您输入的数字将被排序并平方。让我们看三个案例:

  • 如果您的输入只包含正数,那么平方它们将保持排序。Timsort在O(n)时间内检测到了这一点,并且不做任何其他事情
  • 如果您的输入只包含负数,则平方将使其按相反顺序排序。例如,
    [-5,-4,-2,-1]
    变为
    [25,16,4,1]
    。Timsort检测到这一点并简单地反转列表。时间又到了
  • 如果您的输入同时包含负数和正数,那么在平方后,您将有一个降序运行,然后是一个升序运行。然后,Timsort检测这两个运行,反转下降运行,并对两个运行进行简单合并。时间又到了

所以。。。内置的
排序
和您自己的排序都是O(n)。但是
sorted
是在C级别实现的,它更快,并且可以访问快捷方式,从而使其具有更小的隐藏常量。

LeetCode报告的时间是对解决方案进行测试的所有测试用例的总和。作为算法效率的衡量标准,这是非常不可靠的,因为

  • 大多数测试用例都在小输入上
  • 法官本身所花费的开销时间是巨大的,而且变化很大,因此,即使两个测量值之间存在适度差异,也可能仅仅取决于该开销中的随机变化
有关更多讨论,请参阅


因此,如果我们想比较这两种算法的性能,最好自己做。我做到了;以下是我的次数,最多可列出5000次(平均每次超过1000次):

以下是我列出的最大1000000个列表的时间(无平均值):

正如您所见,使用
sorted
对于小输入和大输入都始终更快,因此LeetCode这次的比较实际上是正确的(尽管可能只是巧合!)。您的解决方案确实是线性时间,这些结果与此一致。但是使用
排序的解决方案似乎也需要线性时间,堆溢出的答案解释了为什么应该这样做


我的计时代码如下。时间是使用Python3.5.2测量的,我使用Python3.8.1得到了类似的结果

def线性(A):
开始=0
结束=透镜(A)-1
B=[]
当开始=abs(A[结束])时:
附加(A[start]*A[start])
开始+=1
其他:
追加(A[end]*A[end])
结束-=1
B.反向()
返回B
def使用_排序(A):
已排序的返回值(x*x表示A中的x)
从timeit导入timeit
从随机导入randint
打印('n','linear','using sorted',sep='\t')
对于范围(10000、1000001、10000)内的n:
数据=已排序(范围(n)内i的randint(-10*n,10*n))
t1=时间(λ:线性(数据),数字=1)
t2=时间(λ:使用_排序(数据),数字=1)
打印(n,t1,t2,sep='\t')

哪一个是您的输入?仅供参考:算法已经在输入时消失了
[1,3,2]
。“O(n)排序”总是可疑的。@tevemadar在这个问题中对输入数组进行了排序,但是是的,OP肯定应该附加问题定义。否则:问题是Python速度不快。当它将用本机代码实现的库连接在一起时,速度很快。内置排序是一种高度优化的mergesort,用C实现,详细描述请参见,实现开始于。编辑:as@DavidL。显示输入已排序,可能值得补充的是,链接排序据说在部分排序的列表上表现非常好。感谢您的回答,我应该更详细地发布问题描述。输入李