从两个排序的数组中找到第k个最小元素

时间:2016-10-22 06:31:38

标签: arrays algorithm time-complexity

给定两个大小为M和N的排序数组。我试图实现时间复杂度为O(logM + logN)的算法。该策略基本上是根据长度条件比较两个子阵列的中间索引元素。

    // Test case 1
    // Works for all position except when kth is 6
    int[] num1 = {6,7,8,9,10,11,12};
    int[] num2 = {1,2,3,4,5};

    // Test case 2
    // Always print the next smallest element
    int[] num3 = {1,3,5,7,9};
    int[] num4 = {2,4,6,8,10,12,14,16,18,20,22,24,30,40,50,56,77,35};


public static int findKth(int[] A, int p1, int r1, int[] B, int p2, int r2, int k){


    if (p1 > r1) { 
        return B[p2+k-1];
    } else if (p2 > r2) {
        return A[p1+k-1];
    }


    int midA = p1 + (int)Math.floor((r1-p1)/2);// Middle element from subarray A
    int midB = p2 + (int)Math.floor((r2-p2)/2);// Middle element from subarray B

    /**
     * Compare the sum of number of elements from left-subarray up to middle element. 
     */
    if ((midA-p1+midB-p2+2) < k) { 
        // We don't need to the left-subarray based on the comparisons between middle element
        if (A[midA] > B[midB]) {
            return findKth(A, p1, r1, B, midB+1, r2, k-(midB-p2+1)); //
        } else {
            return findKth(A, midA+1, r1, B, p2, r2, k-(midA-p1+1)); //
        }
    } else {
        // We don't need to the right-subarray based on the comparisons between middle element.
        if (A[midA] > B[midB]) {
            return findKth(A, p1, midA-1, B, p2, r2, k);
        } else {
            return findKth(A, p1, r1, B, p2, midB-1, k);
        }
    }
}

我觉得我使用的策略应该是正确的。但对于上面显示的两个测试用例,它会以某个特定的第k个值打印错误的输出。所以我猜我的策略一定有问题。谁能简单描述一下这个实现的哪个部分不正确?谢谢!

3 个答案:

答案 0 :(得分:2)

如果我能在您的代码段中找到错误,我会更新我的答案。现在你可以看看我的代码哪个逻辑与你的完全相同,除了:

  

该策略基本上是比较两个中间指数元素   基于长度条件的子阵列。

我的代码的简单性和小尺寸的主要区别是我通过在第一个数组/索引对不小的情况下调用交换其参数的函数来避免一些if-else条件(对于长度条件)。

<script>
        var titleArray = ["TITLE-1","TITLE-2","TITLE-3","TITLE-4"];
        var N = titleArray.length;
        var i = 0;
        setInterval(func,5000);
        function func(){
            if (i == 4) {
                i = 0;
            }
            document.title = titleArray[i];
            i++;
        }

</script>

时间复杂度为public static int findKth(int[] A, int i, int[] B, int j, int k) { // Here is the simple trick. We've just changed the parameter order if first array is not smaller. // so that later we won't need to write if-else conditions to check smaller/greater stuff if((A.length - i) > (B.length - j)) { return findKth(B, j, A, i, k); } if(i >= A.length) { return B[j + k - 1]; } if(k == 1) { return Math.min(A[i], B[j]); } int aMid = Math.min(k / 2, A.length - i); int bMid = k - aMid; if(A[i + aMid - 1] <= B[j + bMid - 1]) { return findKth(A, i + aMid, B, j, k - aMid); } return findKth(A, i, B, j + bMid, k - bMid); } public static int findKthSmallestElement(int[] A, int[] B, int k) { if(k > A.length + B.length) return -1; return findKth(A, 0, B, 0, k); }

答案 1 :(得分:0)

StackOverflow上已经有很好的解决方案,例如herehere,所以我将专注于识别错误:

这一行:

if ((midA-p1+midB-p2+2) < k) { 

应修改为使用<=

if ((midA-p1+midB-p2+2) <= k) { 

您可以通过以下小例子了解为什么需要这样做:

A = {1,3}
B = {2}

其他变量将是:

p1 = p2 = r2 = midA = midB = 0
r1 = 1

所以表达式midA-p1+midB-p2+2将是2。在这种情况下,你显然想要丢弃A的元素,而不是B的唯一元素。

请注意,通常可以包含 k 案例来执行if块,因为你永远不会丢弃 k (即太多)元素:作为递归调用的最后一个参数传递的表达式总是最多 k-1

另一方面,当else表达式 k 时转到if部分是错误的,因为 midA midB 可能是 k th 元素的索引, 将被抛出。

答案 2 :(得分:0)

#include <bits/stdc++.h>
using namespace std;

int findKthElement(int a[],int start1,int end1,int b[],int start2,int end2,int k){
    if(start1 >= end1)return b[start2+k-1];
    if(start2 >= end2)return a[start1+k-1];
    if(k==1)return min(a[start1],b[start2]);
    int aMax = INT_MAX;
    int bMax = INT_MAX;
    if(start1+k/2-1 < end1) aMax = a[start1 + k/2 - 1];
    if(start2+k/2-1 < end2) bMax = b[start2 + k/2 - 1];

    if(aMax > bMax){
        return findKthElement(a,start1,end1,b,start2+k/2,end2,k-k/2);
    }
    else{
        return findKthElement(a,start1 + k/2,end1,b,start2,end2,k-k/2);
    }
}

int main(void){
    int t;
    scanf("%d",&t);
    while(t--){
        int n,m,k;
        cout<<"Enter the size of 1st Array"<<endl;
        cin>>n;
        int arr[n];
        cout<<"Enter the Element of 1st Array"<<endl;
        for(int i = 0;i<n;i++){
            cin>>arr[i];
        }
        cout<<"Enter the size of 2nd Array"<<endl;
        cin>>m;
        int arr1[m];
        cout<<"Enter the Element of 2nd Array"<<endl;
        for(int i = 0;i<m;i++){
            cin>>arr1[i];
        }
        cout<<"Enter The Value of K";
        cin>>k;
        sort(arr,arr+n);
        sort(arr1,arr1+m);
        cout<<findKthElement(arr,0,n,arr1,0,m,k)<<endl;
    }

    return 0;
}

Time Complexcity是O(log(min(m,n)))