此代码首先迭代列表
nums
,更新整数 0、1、2(也分别称为红色、白色和蓝色)的计数。
nums
保证只有整数 0、1 和/或 2。找到计数后,代码使用
[::]
,这是一种就地修改列表的技巧,以排序
nums
def sortColors(self, nums: List[int]) -> None:
red = white = blue = 0
for num in nums:
match num:
case 0:
red += 1
case 1:
white += 1
case 2:
blue += 1
# [::] to modify nums in-place - Space O(1)
nums[::] = ([0] * red) + ([1] * white) + ([2] * blue)
return nums
我认为
([0] * red) + ([1] * white) + ([2] * blue)
将在修改 nums 之前进行评估,这意味着该列表必须是在
nums[::] =
可以继续之前创建并存储在内存中。对我来说,这是有道理的,因为在 Python 中,
=
的右侧是在变量赋值之前评估的,这使得像
x = x + 1
这样的东西可以工作。因此,根据这种理解,代码中的此时,原始
nums
列表和新列表都将存储在内存中。因为新列表的长度与
nums
相同,所以需要 O(n) 额外空间。
但是,分析工具表示此代码是 O(1) 空间。我唯一能想到的是,调用
nums[::] =
的那一刻,代码忽略了nums原来的内容,将nums就地修改为新列表。
这个O(1)空间怎么样,是我对空间复杂度和变量赋值的理解正确吗?
分析工具是正确的,此代码的空间复杂度为 O(1) 。的理解几乎是正确的,但关键在于 Python 如何处理列表切片及其赋值。
是对的,在 Python 中,赋值运算符 (
=
) 右侧的表达式会在赋值之前求值。因此,
([0] * red) + ([1] * white) + ([2] * blue)
确实会在
nums[::] = ...
发生之前创建
新
列表。
但是,误解了
nums[::] = ...
的工作原理。这不是将
nums
替换为新列表的简单赋值。相反,它
就地
修改了
nums
的内容。
以下是它的工作原理:
-
切片赋值:
nums[::]
是nums
本身的切片,它表示整个列表。使用切片赋值时,Python 会将右侧的值解释为要放置在切片位置的序列。 -
就地修改:
Python 认识到它可以有效地修改现有列表,而不是创建全新的列表。它遍历右侧的序列(由连接的
[0] * red
、[1] * white
和[2] * blue
列表组成),并将这些值直接写入nums
,从索引 0 开始。 -
垃圾回收:
连接操作创建的临时列表在分配给
nums[::]
后就不再需要,并由 Python 的垃圾回收器回收。
总之
,虽然创建了一个新列表来保存排序后的元素,但它是临时的,并且在
nums[::] = ...
完成执行之前被销毁。
nums
的修改是就地完成的,导致 O(1) 的空间复杂度。的代码不会使用与其输入大小成比例的额外空间。
的混淆很常见,理解 Python 如何处理切片赋值及其对空间复杂度的影响至关重要。
标签:python,arrays,algorithm From: 78829950