繁体   English   中英

在排序数组的并集中查找第k个最小元素

[英]Finding the kth-smallest element in union of sorted arrays

我正在研究关于在leetcode中找到两个排序数组的并集中的第k个最小元素的文章。 我不认为算法是正确的。 有这条线: 我们观察到当Ai <Bj时,那么Ai <Bj-1必定是真的。 另一方面,如果Bj <Ai,则Bj <Ai-1。 对于任何ij它怎么可能都是真的?

其次,这条线也让我困惑: 我们试图通过比较A和B的中间元素来解决这个棘手的问题,我们将其识别为Ai和Bj。 如果Ai在Bj和Bj-1之间,我们刚刚找到了i + j + 1最小元素 ,尽管它是真实的。 任何人都可以解释原因吗? 我真的想要理解算法,我已经通过合并数组来完成它,但是这需要O(N)时间,而这里需要O(log N)时间。

你是孤立地解释这些陈述,但它们是相互依赖的。 这是(我认为)你所指的文字:

维持不变i + j = k - 1,如果Bj-1 <Ai <Bj,那么Ai必须是第k个最小的,否则如果Ai-1 <Bj <Ai,那么Bj必须是第k个最小的。 如果满足上述条件之一,我们就完成了。 如果没有,我们将使用i和j作为细分索引来细分数组。 但是怎么样? 我们应该丢弃哪部分? 艾和Bj本身怎么样?

我们观察到当Ai <Bj时,那么Ai <Bj-1必定是真的。 另一方面,如果Bj <Ai,则Bj <Ai-1。 为什么?

将其分解为子命题会产生以下解释(请记住,索引从0开始,但A0是第一个最小项, A1第二个最小项,依此类推):

  1. i + j = k - 1 (根据定义不变)
  2. 假设Bj-1 < Ai < Bj 然后Ai必须是最小的第k个。 这是因为Ai大于A i项并且大于B j项。 所以它总共大于i + j = k - 1项。 这意味着它在合并的A|B列表中的索引将是k - 1 ,因此它将是该列表中的第k个项目。
  3. 假设Ai-1 < Bj < Ai 那么Bj必须是第k个最小的,通过2中相同的推理线。
  4. 现在认为(a) Bj-1 < Ai < Bj和(b) Ai-1 < Bj < Ai都是假的 然后很明显,如果Ai < BjA1 < Bj-1 ,否则(a)将成立。 同样,如果Bj < Ai然后Bj < Ai-1 ,否则,(b)将是真的。

我告诉你,你想要解释这些陈述而不是整个算法。 (但如果你愿意,我会说更多。)

还要注意,正如Daniel Fischer的回答提醒我的那样,只有没有重复的情况下,上述推理才有效; 称这个命题为0。

我们观察到当Ai < Bj ,那么Ai < Bj-1必定是真的。 另一方面,如果Bj < Ai ,那么Bj < Ai-1 ..对于任何ij它怎么可能是真的?

对于所有ij对都不是这样。 文章考虑了一个特殊情况。

首先,假设没有重复,甚至没有AB的共同元素的形式。 第二,结论是

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 ,存在小于Bj j元素,并且在阵列A ,存在小于Ai i元素(索引从0开始)。 因此,如果Bj-1 < Ai < Bj ,则两个阵列一起恰好包含小于Ai j + i元素。

如果有重复,会有什么变化?

不多。

我们仍然考虑i + j = k-1 我们假设Ai <= Bj

  1. 如果Ai = Bj怎么办?
  2. 如果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)的情况下,我们在B中有不大于Ai j元素,并且它们都严格地小,并且我们在A中有m <= i元素,它们严格小于Aim如上)和未知数字,但至少i-m+1元素等于Ai 因此,两个阵列中的j + m <= j + i = k-1元素恰好小于Ai ,并且至少j + m + (i-m+1) = j+i+1 = k元素不大于Ai ,因此两个数组的第k个最小元素一起等于Ai

在情况b)中,相同的推理表明两个阵列的第k个最小元素一起等于Ai

在剩下的情况下, Ai < Bj-1 ,事情变得不复杂了。 数组B至少包含不大于Bj-1 j元素,并且数组A至少包含严格小于Bj-1 i+1元素,因此两个数组的第k个最小元素一起最多与Bj-1一样大Bj-1 但它不能比较小AiB含有至多j-1更小的元素比Ai ,因此两个阵列一起含有至多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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM