我正在回答关于网上法官的问题。解决方案的一部分如下所示:
if j > 0 and i < m and B[j-1] > A[i]:
imin = i + 1
elif i > 0 and j < n and A[i-1] > B[j]:
imax = i - 1
它毫无问题地通过了法官。
但是,如果我将其更改为
if j > 0 and i < m:
if B[j-1] > A[i]:
imin = i + 1
elif i > 0 and j < n:
if A[i-1] > B[j]:
imax = i - 1
法官立刻告诉我,即使是在非常简单的测试案例中,我也超过了时间限制。
我相信两段代码在逻辑上是等价的(当然我可能在这里错了。如果是这样的话,请纠正我。)。通过将并行and
更改为嵌套if
,它让我感到惊讶。我的假设是对的吗?如果是这样,为什么会发生这种情况,它会产生多大的差异?
(抱歉,我无法提供程序运行的确切时间,因为在线评委并不知道运行测试用例需要多少。整个功能可在{{3}处获得问题是here。它是关于找到两个排序数组的中位数。失败的测试用例包括[1], [1]
和[1,1], [1,1]
)
整个功能:
def median(A, B):
m, n = len(A), len(B)
if m > n:
A, B, m, n = B, A, n, m
if n == 0:
raise ValueError
imin, imax, half_len = 0, m, (m + n + 1) / 2
while imin <= imax:
i = (imin + imax) / 2
j = half_len - i
if j > 0 and i < m and B[j-1] > A[i]:
# i is too small, must increase it
imin = i + 1
elif i > 0 and j < n and A[i-1] > B[j]:
# i is too big, must decrease it
imax = i - 1
else:
# i is perfect
if i == 0: max_of_left = B[j-1]
elif j == 0: max_of_left = A[i-1]
else: max_of_left = max(A[i-1], B[j-1])
if (m + n) % 2 == 1:
return max_of_left
if i == m: min_of_right = B[j]
elif j == n: min_of_right = A[i]
else: min_of_right = min(A[i], B[j])
return (max_of_left + min_of_right) / 2.0
答案 0 :(得分:5)
将if
嵌入到内部既不快也不慢, Python 第一个if
测试编译为完全相同的字节码,如果采用孤立地:
>>> import dis
>>> dis.dis(compile('''\
... if j > 0 and i < m and B[j-1] > A[i]:
... pass
... ''', '', 'exec'))
1 0 LOAD_NAME 0 (j)
3 LOAD_CONST 0 (0)
6 COMPARE_OP 4 (>)
9 POP_JUMP_IF_FALSE 48
12 LOAD_NAME 1 (i)
15 LOAD_NAME 2 (m)
18 COMPARE_OP 0 (<)
21 POP_JUMP_IF_FALSE 48
24 LOAD_NAME 3 (B)
27 LOAD_NAME 0 (j)
30 LOAD_CONST 1 (1)
33 BINARY_SUBTRACT
34 BINARY_SUBSCR
35 LOAD_NAME 4 (A)
38 LOAD_NAME 1 (i)
41 BINARY_SUBSCR
42 COMPARE_OP 4 (>)
45 POP_JUMP_IF_FALSE 48
2 >> 48 LOAD_CONST 2 (None)
51 RETURN_VALUE
>>> dis.dis(compile('''\
... if j > 0 and i < m:
... if B[j-1] > A[i]:
... pass
... ''', '', 'exec'))
1 0 LOAD_NAME 0 (j)
3 LOAD_CONST 0 (0)
6 COMPARE_OP 4 (>)
9 POP_JUMP_IF_FALSE 48
12 LOAD_NAME 1 (i)
15 LOAD_NAME 2 (m)
18 COMPARE_OP 0 (<)
21 POP_JUMP_IF_FALSE 48
2 24 LOAD_NAME 3 (B)
27 LOAD_NAME 0 (j)
30 LOAD_CONST 1 (1)
33 BINARY_SUBTRACT
34 BINARY_SUBSCR
35 LOAD_NAME 4 (A)
38 LOAD_NAME 1 (i)
41 BINARY_SUBSCR
42 COMPARE_OP 4 (>)
45 POP_JUMP_IF_FALSE 48
3 >> 48 LOAD_CONST 2 (None)
51 RETURN_VALUE
上述反汇编中只有行号不同。
但是,您假设elif
分支仍然等效。它不是;因为您移动了第一个if
的测试 ,所以第二个elif
将更频繁地进行测试,与B[j-1] > A[i]
无关;例如如果j > 0 and i < m
为True,但B[j-1] > A[i]
为False,则您的第一个版本将完全跳过elif
测试,但您的第二个版本仍会测试i > 0 and j < n
!
将dis.dis()
输出用于完整的if..elif
测试,并删除除比较和跳转之外的所有内容,您将获得:
6 COMPARE_OP 4 (>)
9 POP_JUMP_IF_FALSE 51
18 COMPARE_OP 0 (<)
21 POP_JUMP_IF_FALSE 51
42 COMPARE_OP 4 (>)
45 POP_JUMP_IF_FALSE 51
48 JUMP_FORWARD 48 (to 99)
57 COMPARE_OP 4 (>)
60 POP_JUMP_IF_FALSE 99
69 COMPARE_OP 0 (<)
72 POP_JUMP_IF_FALSE 99
93 COMPARE_OP 4 (>)
96 POP_JUMP_IF_FALSE 99
>> 99 LOAD_CONST 2 (None)
102 RETURN_VALUE
表示您的初始版本,但将and
部分移动到单独的嵌套if
测试中:
6 COMPARE_OP 4 (>)
9 POP_JUMP_IF_FALSE 51
18 COMPARE_OP 0 (<)
21 POP_JUMP_IF_FALSE 51
42 COMPARE_OP 4 (>)
45 POP_JUMP_IF_FALSE 99
48 JUMP_FORWARD 48 (to 99)
57 COMPARE_OP 4 (>)
60 POP_JUMP_IF_FALSE 99
69 COMPARE_OP 0 (<)
72 POP_JUMP_IF_FALSE 99
93 COMPARE_OP 4 (>)
96 POP_JUMP_IF_FALSE 99
>> 99 LOAD_CONST 2 (None)
102 RETURN_VALUE
注意索引45处的POP_JUMP_IF_FALSE
操作码。一跳到最后(99),另一跳跳转到elif
分支(在索引51处)!
这肯定是代码中的一个错误,导致花费更多时间并且判断代码失败。