Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.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 为什么下面的算法是O(1)空间?_Python_Algorithm_Asymptotic Complexity_Space Complexity - Fatal编程技术网

Python 为什么下面的算法是O(1)空间?

Python 为什么下面的算法是O(1)空间?,python,algorithm,asymptotic-complexity,space-complexity,Python,Algorithm,Asymptotic Complexity,Space Complexity,输入:一个正整数列表,其中一个条目正好出现一次,而所有其他条目正好出现两次(例如[1,3,2,5,3,4,1,2,4]) 输出:唯一条目(上例中为5) 下面的算法应该是O(m)时间和O(1)空间,其中m是列表的大小 def get_unique(intlist): unique_val = 0 for int in intlist: unique_val ^= int return unique_val 我的分析是:给定一个长度为m的列表,输入列表中将有

输入:一个正整数列表,其中一个条目正好出现一次,而所有其他条目正好出现两次(例如[1,3,2,5,3,4,1,2,4])

输出:唯一条目(上例中为5)

下面的算法应该是O(m)时间和O(1)空间,其中m是列表的大小

def get_unique(intlist):
    unique_val = 0
    for int in intlist:
        unique_val ^= int
    return unique_val

我的分析是:给定一个长度为m的列表,输入列表中将有(m+1)/2个唯一的正整数,因此列表中最小的可能最大整数将是(m+1)/2。如果我们假设这是最好的情况,那么在进行异或求和时,变量unique_val将需要内存中的上限(log((m+1)/2))位,因此我认为空间复杂度至少应该是O(log(m))。

您的分析肯定是一个正确答案,特别是在Python这样的语言中,它可以优雅地处理任意大的数字

在考虑空间和时间的复杂性时,清楚地了解您试图衡量的是什么是很重要的。一个合理的假设可能是整数的大小是恒定的(例如,您使用的是64位整数)。在这种情况下,空间复杂度当然是O(1),但时间复杂度仍然是O(m)

现在,您还可以说,使用固定大小的整数意味着
m
的大小有一个恒定的上限,因此时间复杂度也可能是O(1)。但是在大多数情况下,如果你需要分析这种算法的运行时间,你可能对长度为10的列表和长度为10亿的列表之间的差异非常感兴趣

我想说,在分析空间和时间复杂性时,澄清和陈述你的假设是很重要的。在这种情况下,我假设我们有一个固定大小的整数,值
m
比最大整数值小得多。在这种情况下,O(1)空间和O(m)时间可能是最好的答案

编辑(基于其他答案中的讨论)

由于所有
m
给您的都是列表中最大值的下限,因此您确实无法提供空间的最坏情况估计。即列表中的数字可以任意大。要对此算法的空间复杂度给出合理的答案,您需要对输入值的最大大小进行一些假设。

通常(空间/时间)复杂度分析应用于更高级别的算法。虽然您可以下拉到特定的语言实现级别,但它可能并非在所有情况下都有用

你的分析是对的,也可能是错的。它适用于当前的cpython实现,其中整数没有最大值。如果您的所有整数都相对较小,并且适合于实现特定的小数字情况,那么就可以了

但它不一定对所有其他python实现都有效。例如,您可以有一个优化实现,该实现指出不再使用
intlist
,而是使用
unique\u val
,它重用已使用列表元素的空间。(基本上将此函数转换为空间优化的reduce调用)

再说一次,我们甚至可以用分配的整数讨论GC'd语言中的空间复杂性吗?您对复杂性的分析是错误的,因为
a^=b
将为大值
b
分配新内存,而其大小取决于系统、体系结构、python版本和运气


然而,您最初的问题是“为什么下面的算法是O(1)空间?”。如果您查看算法本身并假设您有一些任意的最大整数限制,或者您的语言可以在有限的空间中表示任何数字,那么答案是肯定的。具有这些条件的算法本身使用恒定空间。

算法的复杂性始终取决于您使用的机器模型(=平台)。例如,我们常说IEEE浮点数的乘法和除法具有运行时复杂性O(1)-情况并非总是如此(例如,在没有FPU的8086处理器上)

对于上述算法,只要输入列表中没有大于2147483647(=sys.maxint)的元素,空间复杂度O(1)就保持不变。通常,python将整数存储为带符号的32位值。对于这些数据类型,您的处理器已经在硬件中实现了所有相关操作,通常只需要固定数量的时钟周期(在大多数情况下只有一个)来执行它们(=运行时复杂性O(1)),并且只占用固定数量的内存地址(只有一个)来存储结果(=空间复杂性O(1))


但是,如果输入超过2147483647,python通常使用软件实现的数据类型来存储这些大整数。这些操作不再在O(1)中,它们需要的不仅仅是常数O(1)空间。

它在空间中是O(1),因为它只使用单个变量
unique\u val
(它是标量,而不是列表、元组等),而不管输入列表的大小。如果将内存单元建模为位或字节,则为O(log(m)),而O(1)如果将内存单元建模为包含任意大小的整数。这两种模型都用于复杂性分析(和其他模型一样),但复杂性分析的基本原理并不像你想象的那样清晰。根据问题陈述,长度m意味着其中至少有一个大小(m+1)/2的值。我认为如果我的分析是正确的,它至少和O(logm)空间一样糟糕,因此O(1)空间不可能是一个上限。我自己也不相信,我仍然不太明白发生了什么:)答案很有帮助。谢谢,这就是我所困惑的。问题陈述/解决方案似乎告诉我,我可以在任意列表上获得O(1)个空间,但随后存储大小将随着O(logm)的增加而增加。因此,在这种情况下,我可以限制输入的大小,我同意O(1)空间,但正如你所说,列表的长度是有界的,似乎我们也得到了O(1)时间。我是