leetcode-Median of Two Sorted Arrays

描述:

    There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log(m+n)).

分析:

   其实这题更通用的形式是,给定两个已经排好序的数组,找到两者所有元素中第k大的元素。

   O(m+n)的解法比较直观,直接merge两个数组,然后取第k个元素即可。

   不过我们仅仅需要第k大的元素,是不需要“排序”这么复杂的操作的。可以用一个计数器,记录当前已经找到第m大的元素,同时我们使用两个指针pA和pB,分别指向A和B数组的第一个元素,使用类似于merge sort的原理,如果数组A当前元素小,那么pA++,同时m++;如果数组B当前元素小,那么pB++,m++。最终当m等于k的时候,就得到了我们的答案,O(k)时间,O(1)空间。如果当k接近m+n的时候,这个方法还是O(m+n)的。

实现代码:

#include<stdio.h>
static int g_InvlidInput = 0;
int find_kth(int A[],int m, int B[], int n,int k)
{
    if((m+n)<k)
    {
        g_InvlidInput = 1;
        return -1;
    }
    int kth = 0,kthindex = 0,Aindex = 0,Bindex = 0;
    int *pA = A;
    int *pB = B;
    while((kthindex < k) && (Aindex < m) && (Bindex < n))
    {
        if(pA[Aindex] <pB[Bindex])
        {
            kth = pA[Aindex];
            Aindex++;
        }else
        {
            kth = pB[Bindex];
            Bindex++;
        }
        kthindex++;
    }
    if(kthindex == k)
        return kth;
    else
    {
        if(Aindex == m) return pB[Bindex+k-kthindex];
        if(Bindex == n) return pA[Aindex+k-kthindex];
    }
}

//test
int main()
{
    int A[] ={1,4,5,7,9,22,44,78};
    int B[] ={2,4,7,11,12,23,45};
    int result = find_kth(A,8,B,7,8);
    if(g_InvlidInput)
        printf("Invaild Input!");
    else 
        printf("%d
",result);
    return 0;
}

除了这个方案,还有没有更好的方案呢?有。我们可以考虑从k入手。如果我们每次都删除一半呢》由于A和B都是有序的,我们应该充分利用这里面的信息,类似于二分查找,也是充分利用了“有序”。

假设A和B的元素个数都大于k/2,我们将A的第k/2个元素(即A[k/2-1])和B的第k/2个元素(即B[k/2-1])进行比较,有以下三种情况(为了简化这里先假设k为偶数,所得到的结论对于k为奇数也是成立的):

  • A[k/2-1] == B[k/2-1]
  • A[k/2-1]  >  B[k/2-1]
  • A[k/2-1]  <  B[k/2-1]

如果A[k/2-1] < B[k/2-1] ,意味着A[0]到A[k/2-1]的元素肯定在AUB的top k元素的范围内,也就是说,A[K/2-1]不可能大于AUB的第k大元素。

因此,我们可以放心的删除A数组的这k/2个元素。同理,当A[k/2-1] > B[k/2-1]时,可以删除B数组的k/2个元素。

当A[k/2-1] == B[k/2-1]时,说明找到了第k大的元素,直接返回A[k/2-1]或B[k/2-1]即可。

因此,我们可与写一个递归函数,那么函数该什么时候终止呢?

  • 当A或B是空时,直接返回B[k-1]或A[k-1];
  • 当k=1时,返回min(A[0],B[0]);
  • 当A[k/2-1] == B[k/2-1]时,返回A[k/2-1]或B[k/2-1]

实现代码:

#include<stdio.h>
int min(int a, int b)
{
    if(a>b)
        return b;
    else
        return a;
}
int find_kth(int A[],int m, int B[], int n,int k)
{
    //保证m比n小
    if(m >n) return find_kth(B,n,A,m,k);
    if(m == 0) return B[k-1];
    if(k == 1) return min(A[0],B[0]);

    //将k拆分成两个部分
    int pa = min(k/2,m),pb = k -pa;
    if(A[pa-1] < B[pb-1])
        return find_kth(A+pa,m-pa,B,n,k-pa);
    else if( A[pa-1] >B[pb-1])
        return find_kth(A,m,B+pb,n-pb,k-pb);
    else
        return A[pa-1];
}

//test
int main()
{
    int A[] ={1,4,5,7,9,22,44,78};
    int B[] ={2,4,7,11,12,23,45};
    int result = find_kth(A,8,B,7,10);
    printf("%d
",result);
    return 0;
}
原文地址:https://www.cnblogs.com/neyer/p/4519399.html