在C/C++中,交换两个数的常规方法有以下两种:
tmp = a
a = b
b = tmp
a = a + b
b = a - b
a = a - b
但是在Python中,还有一种更简便的方法:
a, b = b, a
# 或 b, a = a, b
这种方法在一般情况下可以很容易的完成变量交换,甚至在数组中一般情况也是成立的。但是这两天在刷Leetcode时, 题目:缺失的第一个正数,碰到了一个问题,在对数组中的两个值进行交换的时候,即将nums[i]
和nums[nums[i]-1]
交换时,下面的两个语句,只有第二个语句是正确的:
nums[i], nums[nums[i] - 1] = nums[nums[i] - 1], nums[i]
nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1]
究其原因,明白了置换操作的原理就可以很容易理解。
我们通过查看置换前后变量a
,b
的地址去理解,看下面的例子:
a,b = 1,2
print("-----置换前------")
print(a,b)
print("a的地址:", id(a))
print("b的地址:", id(b))
a,b = b,a
print("-----置换后------")
print(a,b)
print("a的地址:", id(a))
print("b的地址:", id(b))
输出结果是
-----置换前------
1 2
a的地址: 4444362368
b的地址: 4444362400
-----置换后------
2 1
a的地址: 4444362400
b的地址: 4444362368
可以看到,python中对变量的赋值是改变变量的指向,将变量指向目标值的地址。
所以,对于置换操作a, b = b, a
,操作顺序是先计算得到等号右边的所有数值,再将值依次赋给等号的左边。
再回到上面出问题的例子
错误的:
nums[i], nums[nums[i] - 1] = nums[nums[i] - 1], nums[i]
正确的:
nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1]
问题就出在计算得到等式右边后,将值「依次」赋给等号的左边。可以看到nums[nums[i] - 1]
引用了nums[i]
。具体来说,对于错误的,由于nums[nums[i] - 1]
引用了nums[i]
,而这时的nums[i]
已经重新赋值完毕,所以不正确。
总结一下,对于置换操作a, b = b, a
,原理是计算得到等式右边后,将值「依次」赋给等号的左边。然后如果a
和b
存在引用关系,特别是在数组中,特别注意后者不能引用前者。