我们观察到,当Ai < Bj 时,Ai < Bj-1 一定是真的。另一方面,如果Bj < Ai,那么Bj < Ai-1.. 任何i 和j 怎么可能是真的?
并非所有 i 和 j 对都是如此。文章考虑了一种特殊情况。
首先,假设没有重复,即使是A 和B 的共同元素的形式。二、结论
Ai < Bj ==> Ai < Bj-1, resp. Bj < Ai ==> Bj < Ai-1
是在都没有
的条件下制作的
Bj-1 < Ai < Bj resp. Ai-1 < Bj < Ai
持有。因此,通过排除这些配置,Ai < Bj ==> Ai <= Bj-1 和 Bj < Ai ==> Bj <= Ai-1 立即紧随其后,严格不等式紧随其后,假设不存在重复。
我们尝试通过比较 A 和 B 的中间元素(我们将其识别为 Ai 和 Bj)来解决这个棘手的问题。如果Ai在Bj和Bj-1之间,我们刚刚找到了第i+j+1个最小元素
在数组B中,有j元素小于Bj,在数组A中,有i元素小于Ai(索引从0开始)。所以如果Bj-1 < Ai < Bj,两个数组一起正好包含小于Ai的j + i元素。
如果有重复,会发生什么变化?
不多。
我们还是考虑i + j = k-1的情况。让我们假设Ai <= Bj。
- 如果
Ai = Bj怎么办?
- 如果
Ai < Bj怎么办?
在情况 1. 中,设m 是满足Am = Ai 的最小索引,而n 是满足Bn = Bj 的最小索引。然后在两个数组中,恰好有严格小于Ai 的m + n <= i + j = k-1 元素,并且至少有不大于Ai 的(i+1) + (j+1) = (k+1) 元素。因此第 k 个最小的元素等于Ai。
对于 2.,我们需要考虑三种情况,a)Bj-1 < Ai,b)Bj-1 = Ai,c)Bj-1 > Ai。
在情况 a) 中,B 中的 j 元素不大于 Ai,并且它们都严格小于,A 中的 m <= i 元素严格小于Ai(m 同上)和一个未知数,但至少 i-m+1 元素等于 Ai。所以两个数组中恰好有j + m <= j + i = k-1元素一起严格小于Ai,并且至少j + m + (i-m+1) = j+i+1 = k元素不大于Ai,因此两个数组的第k个最小元素一起等于@ 987654373@.
在情况 b) 中,同样的推理表明两个数组的第 k 个最小元素加起来等于 Ai。
在剩下的情况下,Ai < Bj-1,事情变得几乎没有更复杂。数组B 至少包含不大于Bj-1 的j 元素,数组A 至少包含严格小于Bj-1 的i+1 元素,因此两个数组的第k 个最小元素加在一起为最大为Bj-1。但它不能小于Ai(B 最多包含小于Ai 的元素j-1,因此两个数组一起最多包含小于i + (j-1) = k-2 的元素Ai)。
所以我们仍然可以从数组A 中丢弃Ai 以下的部分,从数组B 中丢弃Bj-1 以上的部分,并继续进行,没有重复。
所有的改变是一些严格的不等式必须被弱不等式取代。
代码(如果传递起始索引和长度而不是切片,效率会更高,但切片会产生更短的代码):
def kthsmallest(A, B, k):
if k < 1:
return None
a_len, b_len = len(A), len(B)
if a_len == 0:
return B[k-1] # let it die if B is too short, I don't care
if b_len == 0:
return A[k-1] # see above
# Handle edge case: if k == a_len + b_len, we would
# get an out-of-bounds index, since i + j <= a_len+b_len - 2
# for valid indices i and j
if a_len + b_len == k:
if A[-1] < B[-1]:
return B[-1]
else:
return A[-1]
# Find indices i and j approximately proportional to len(A)/len(B)
i = (a_len*(k-1)) // (a_len+b_len)
j = k-1-i
# Make sure the indices are valid, in unfortunate cases,
# j could be set to b_len by the above
if j >= b_len:
j = b_len-1
i = k-1-j
if A[i] <= B[j]:
if j == 0 or B[j-1] <= A[i]:
return A[i]
# A[i] < B[j-1] <= B[j]
return kthsmallest(A[i:], B[:j], k-i)
# B[j] < A[i], symmetrical to A[i] < B[j]
if i == 0 or A[i-1] <= B[j]:
return B[j]
# B[j] < A[i-1]
return kthsmallest(A[:i], B[j:], k-j)