试图理解这个从两个排序数组中找到第 K 分钟的算法

Posted

技术标签:

【中文标题】试图理解这个从两个排序数组中找到第 K 分钟的算法【英文标题】:Trying to understand this algorithm for finding Kth min from two sorted array 【发布时间】:2014-11-02 06:59:32 【问题描述】:

说明: 给定两个有序数组(非降序),求 T = O(lg(m + n)) 中的第 K 个最小元素,m 和 n 的长度为 2 数组,分别。

问题: 不明白下面的算法大概三点:

当 A[aPartitionIndex] 为什么不能把 A 的左边部分和 B 的右边部分放在 同一时间? 一些“资源”说这个算法可以应用于寻找第 Kth min 在N个排序数组中,如何?把 k 分成 N 份?

代码: Java。 解决方案:二分查找。

    // k is based on 1, not 0.
    public int findKthMin(int[] A, int as, int ae, 
                           int[] B, int bs, int be, int k) 

        int aLen = ae - as + 1;
        int bLen = be - bs + 1;

        // Guarantee the first array's size is smaller than the second one,
        // which is convenient to remaining part calculation.
        if (aLen > bLen) return findKthMin(B, bs, be, 
                                           A, as, ae, k);

        // Base case.
        if (aLen == 0) return B[bs + k - 1];
        if (k == 1) return Math.min(A[as], B[bs]); // k based on 1, not 0.

        // Split k, 
        // one part is distributed to A,
        // the other part is distributed to B.
        int ak = aLen < (k/2)? aLen: k/2;
        int bk = k - ak;

        // *k is based on 1, not 0.
        int aPartitionIndex = as + (ak - 1);
        int bPartitionIndex = bs + (bk - 1);

        if (A[aPartitionIndex] == B[bPartitionIndex]) 
            return A[aPartitionIndex];

         else if (A[aPartitionIndex] < B[bPartitionIndex]) 
            // Drop the left part of A, and
            // do recursion on the right part of A, and
            // the entire current part of B.
            k = k - ak;
            return findKthMin(A, aPartitionIndex + 1, ae, 
                              B, bs, be, k);

         else 
            // Drop the left part of B, and
            // do recursion on the entire current part of A, and
            // the right part of B.
            k = k - bk;
            return findKthMin(A, as, ae, 
                              B, bPartitionIndex + 1, be, k);
        
    

【问题讨论】:

【参考方案1】:

1) 假设AB 按升序排序,A[aPartitionIndex] &lt; B[bPartitionIndex] 意味着A[i] &lt; B[bPartitionIndex] 对所有i &lt; aPartitionIndex

2) 你永远不能删除数组的右边部分,因为你不知道它们在排序中的位置。

【讨论】:

嗨@Code-Apprentice,[1]你强调“升序”,如果我们将它应用于包含重复的数组,这个算法有什么问题吗? [2]我仍然无法理解“为什么我们可以直接删除A的左边部分”,为什么我们可以确定我们的Kth min不在那个部分,你能举一些反例吗?我试图找到反例,但找不到。非常感谢! @Zhaonan 重复和升序排序有什么关系? (也许“非降序”在技术上更准确。) 嗨@Code-Apprentice,感谢您的帮助!但严重的问题仍然是我无法证明为什么我们可以直接删除 A 的左侧部分,似乎删除 A 的左侧部分是非常正确的,但我就是找不到为什么?有反例吗? @Zhaonan 如果这样做是正确的,那么就不可能有 counter 的例子。另一方面,通过一个示例并使用调试器逐步完成算法肯定会阐明它是如何工作的。 你是对的,“如果这样做是正确的,那么就没有反例”。但是我认为应该有一些反例“同时放下A的左边和B的右边”,但我找不到。

以上是关于试图理解这个从两个排序数组中找到第 K 分钟的算法的主要内容,如果未能解决你的问题,请参考以下文章

从两个排序数组中获取前 K 项而不合并它们

如何在两个排序数组的并集中找到第 k 个最小的元素?

排序算法(快速排序)

在未排序的数组中找到第 k 个最大的元素

如何在未排序数组的情况下找到未排序数组中的第k个最小整数?

五分钟理解选择排序算法