我一直在解决一个类似于下面的编码面试问题:
给出一个字符数组A和一个整数数组P,其中P [i]表示元素在置换中i处的位置。例如,当A = <a, b, c, d>
和P = <2, 0, 1, 3>
时,A应该变成<b, c, a, d>
我对此的解决方案如下:
for i in range(len(A)):
while perm[i] != i:
A[i], A[perm[i]] = A[perm[i]], A[i]
perm[i], perm[perm[i]] = perm[perm[i]], perm[i]
这一个给了我无限循环,而下面的一个起作用了
for i in range(len(A)):
while perm[i] != i:
A[perm[i]], A[i] = A[i], A[perm[i]]
perm[perm[i]], perm[i] = perm[i], perm[perm[i]]
我一直认为Python交换快捷方式中的顺序无关紧要,但是我很困惑为什么上面的那个不起作用而下面的那个很好用。
有什么想法吗?
答案 0 :(得分:6)
顺序很重要 ,并且您在结束时创建了代码。在进行任何赋值之前,都会完全计算整个右侧,因此在简单的情况下,这无关紧要。但是比较:
perm[i], perm[perm[i]] = perm[perm[i]], perm[i]
收件人:
perm[perm[i]], perm[i] = perm[i], perm[perm[i]]
在分配给perm[i]
时,第一个分配给perm[i]
的值会影响来自perm[perm[i]]
的值 read ;在第二步中,对perm[perm[i]]
的赋值使用perm[i]
的 old 值确定分配位置,然后 then 赋新的{{ 1}}。
发生这种情况是因为分配是从左到右执行的;采取的步骤依次为:
perm[i]
值(当前解释器中未构建实际的tuple
,但这在逻辑上是发生的)基本上,您遇到了问题,因为您都在分配的左侧以不同的顺序读写相同的值。
答案 1 :(得分:1)
是的,这里的顺序很重要,因为您正在更改从同一列表读取的索引处列表perm
的内容。如果相同索引处的值发生变化,则以不同的顺序分配可以得出不同的结果。
这是它编译成的字节码:顺序为(读,读,读,写,读,写)。
>>> dis.dis('perm[i], perm[perm[i]] = perm[perm[i]], perm[i]')
1 0 LOAD_NAME 0 (perm)
3 LOAD_NAME 0 (perm)
6 LOAD_NAME 1 (i)
9 BINARY_SUBSCR # reads from perm
10 BINARY_SUBSCR # reads from perm
11 LOAD_NAME 0 (perm)
14 LOAD_NAME 1 (i)
17 BINARY_SUBSCR # reads from perm
18 ROT_TWO
19 LOAD_NAME 0 (perm)
22 LOAD_NAME 1 (i)
25 STORE_SUBSCR # writes to perm
26 LOAD_NAME 0 (perm)
29 LOAD_NAME 0 (perm)
32 LOAD_NAME 1 (i)
35 BINARY_SUBSCR # reads from perm
36 STORE_SUBSCR # writes to perm
37 LOAD_CONST 0 (None)
40 RETURN_VALUE
这是另一种方式:顺序是(读,读,读,读,写,写)。
>>> dis.dis('perm[perm[i]], perm[i] = perm[i], perm[perm[i]]')
1 0 LOAD_NAME 0 (perm)
3 LOAD_NAME 1 (i)
6 BINARY_SUBSCR # reads from perm
7 LOAD_NAME 0 (perm)
10 LOAD_NAME 0 (perm)
13 LOAD_NAME 1 (i)
16 BINARY_SUBSCR # reads from perm
17 BINARY_SUBSCR # reads from perm
18 ROT_TWO
19 LOAD_NAME 0 (perm)
22 LOAD_NAME 0 (perm)
25 LOAD_NAME 1 (i)
28 BINARY_SUBSCR # reads from perm
29 STORE_SUBSCR # writes to perm
30 LOAD_NAME 0 (perm)
33 LOAD_NAME 1 (i)
36 STORE_SUBSCR # writes to perm
37 LOAD_CONST 0 (None)
40 RETURN_VALUE
因此第一个能够读取在同一行中写入的值,因为它先写入后再读取。但是第二个则不能,因为它会在写入任何内容之前先进行所有读取。
老实说,我认为您永远不应该编写这样的代码,因为即使运气很好,它也会使您感到困惑,这并不令人理解-应该应该做什么,更不用说了它做什么。声明一个j = perm[i]
之类的变量,然后编写perm[i], perm[j] = perm[j], perm[i]
,该代码将易于理解,而且绝对不是魔术。