我们观察到什么时候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 个最小元素
在 arrayB
中,有j
小于 的元素Bj
,在 arrayA
中,有i
小于 的元素Ai
(索引从 0 开始)。因此,如果Bj-1 < Ai < Bj
,两个数组一起正好包含j + i
小于 的元素Ai
。
如果有重复,会有什么变化?
不多。
我们还是考虑一下情况i + j = k-1
。让我们假设Ai <= Bj
。
- 万一
Ai = Bj
呢?
- 万一
Ai < Bj
呢?
在情况 1. 中,设m
为 的最小索引Am = Ai
,以及n
的最小索引Bn = Bj
。然后在两个数组中,恰好有m + n <= i + j = k-1
严格小于 的元素Ai
,并且至少有(i+1) + (j+1) = (k+1)
不大于 的元素Ai
。因此,第 k 个最小的元素等于Ai
。
对于 2.,我们需要考虑三种情况,a) Bj-1 < Ai
、b) Bj-1 = Ai
、c) Bj-1 > Ai
。
在情况 a) 中,我们有不大于 的j
元素,并且它们都严格小于,并且我们有严格小于(如上所述) 和未知数的元素,但至少有等于 的元素。因此,两个数组中恰好有元素严格小于,并且至少元素不大于,因此两个数组的第 k 个最小元素一起等于。B
Ai
m <= i
A
Ai
m
i-m+1
Ai
j + m <= j + i = k-1
Ai
j + m + (i-m+1) = j+i+1 = k
Ai
Ai
在情况 b) 中,同样的推理表明两个数组的第 k 个最小元素加起来等于Ai
。
在剩下的情况下Ai < Bj-1
,事情几乎不会变得更复杂。数组B
至少j
包含不大于的元素Bj-1
,并且数组A
至少i+1
包含严格小于的元素Bj-1
,因此两个数组中第 k 个最小的元素加起来最多为Bj-1
。但它不能小于Ai
(B
最多包含j-1
小于的元素Ai
,因此两个数组一起最多i + (j-1) = k-2
包含小于的元素Ai
)。
所以我们仍然可以从数组中丢弃下面Ai
的部分,从数组中丢弃A
上面的部分,并继续进行,没有重复。Bj-1
B
改变的只是一些严格的不等式必须用弱不等式代替。
代码(如果传递起始索引和长度而不是切片会更有效,但切片会产生更短的代码):
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)