leetcode中有一道题。题目为:
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
错误代码:
class Solution:def removeElement(self, nums: List[int], val: int) -> int:for i in nums:print('----', i)if i == val:nums.remove(val)print(len(nums),nums)print(nums)return len(nums)
正确代码:
class Solution:def removeElement(self, nums: List[int], val: int) -> int:for i in nums[:]:print('----', i)if i == val:nums.remove(val)print(len(nums),nums)print(nums)return len(nums)
从以上可以看到,他们之间差了一个[:]
但是单独执行:
for i in nums[:]:print('i',i)for ii in nums:print('ii',ii)
输出结果一抹抹一样样,这是为什么呢?
在 Python 中,nums
是一个列表对象。nums[:]
表示对这个列表进行切片操作,切片操作的结果是返回一个新的列表对象,其中包含了原列表中的所有元素。
虽然 nums
和 nums[:]
看起来很相似,但它们之间有一个重要的区别。当你将 nums
分配给某个变量时,该变量实际上仅仅是指向了原始列表对象的引用,因此对该变量的任何更改都会反映在原始列表对象上。例如:
nums = [1, 2, 3]
new_nums = numsnew_nums[0] = 0print(nums) # 输出 [0, 2, 3]
然而,如果你使用 nums[:]
来创建一个新的列表对象,则对新列表对象的任何更改都不会影响原始列表对象。例如:
nums = [1, 2, 3]
new_nums = nums[:]new_nums[0] = 0print(nums) # 输出 [1, 2, 3]
在这个例子中,我们使用 nums[:]
创建了一个新的列表对象 new_nums
,并将其赋值给变量 new_nums
。然后我们修改了 new_nums
中的第一个元素,但是原始列表 nums
没有被修改。
因此,nums
和 nums[:]
的区别在于,前者是一个指向原始列表对象的引用,而后者是一个新的、独立的列表对象。
由此可以解释上列leetcode题解了。实际上切片是生成了一个新的拷贝。而不是引用。