求两个有序序列合并成新有序序列的中位数,求第k小数

Posted 32ddd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求两个有序序列合并成新有序序列的中位数,求第k小数相关的知识,希望对你有一定的参考价值。

此算法涉及一个重要数学结论:如果A[k/2-1]<B[k/2-1],那么A[0]~A[k/2-1]一定在第k小的数的序列当中,可以用反证法证明。

更加一般的结论是:k=pa+pb,如果A[pa-1]<B[pb-1],那么A[0]~A[pa-1]一定在第k小的数的序列当中。

算法思想如下:

1,假设A长度为m,B长度为n,m>n,反之亦然。

2,拆分k=pa+pb。

3,如果A[pa-1]<b[pb-1],那证明第A[0]~A[pa-1]一定在合并后k小数序列中。所以,可以把A的前面pa个数字截掉,递归,同理砍掉B数组。

4,递归的边界条件是if m=0,返回B[k-1],如果k = 1(找第一个数)就返回min[A[1],B[1])。

 

C++代码

double findKth(int a[], int m, int b[], int n, int k)
{
    //always assume that m is equal or smaller than n
    if (m > n)
        return findKth(b, n, a, m, k);
    if (m == 0)
        return b[k - 1];
    if (k == 1)
        return min(a[0], b[0]);
    //divide k into two parts
    int pa = min(k / 2, m), pb = k - pa;
    if (a[pa - 1] < b[pb - 1])
        return findKth(a + pa, m - pa, b, n, k - pa);
    else if (a[pa - 1] > b[pb - 1])
        return findKth(a, m, b + pb, n - pb, k - pb);
    else
        return a[pa - 1];
}

class Solution
{
public:
    double findMedianSortedArrays(int A[], int m, int B[], int n)
    {
        int total = m + n;
        if (total & 0x1)
            return findKth(A, m, B, n, total / 2 + 1);
        else
            return (findKth(A, m, B, n, total / 2)
                    + findKth(A, m, B, n, total / 2 + 1)) / 2;
    }
};

 

Java代码

import java.util.Arrays;

public class KNumber {
    public int findKth(int[] a, int m, int[] b, int n, int k)
    {   //假设m<n
        if(m>n)
            return findKth(b,n,a,m,k);
        if(m == 0)
            return b[k-1];
        if(k == 1)
            return Math.min(a[0], b[0]);
        //把k分成两部分,结论,if a[pa-1]<b[k-pa-1] 则 a[pa]在有序系列a和b组成的新有序序列中的前k小序列里。
        int pa = Math.min(k/2, m), pb = k - pa;
        if(a[pa - 1] < b[pb - 1])
        {
            int[] tmp = Arrays.copyOfRange(a, pa, a.length);//注意边界是a.length不是a.length-1,java对数组的操作不如c++指针那么方便
            return findKth(tmp,m-pa,b,n,k-pa);
        }
        else if(a[pa-1] > b[pb -1])
        {
            int[] tmp = Arrays.copyOfRange(b, pb, b.length);
            return findKth(a, m, tmp, n-pb, k-pb);
        }
        else
            return a[pa-1];
    }
    
    
    public int findMedianSortedArrays(int[] a, int m, int[] b, int n)
    {
        int total = m + n;
        if(total%2==1)
        {
            return findKth(a, m, b, n, total/2);
        }
        else
            return (findKth(a, m, b, n, total/2)+findKth(a, m, b, n, total/2+1))/2;
    }
    
    
    public static void main(String[] args)
    {
        int[] a = {1,4,9};
        int[] b = {4,5,6};
        KNumber kn = new KNumber();
        System.out.println(kn.findMedianSortedArrays(a, 3, b, 3));
    }
}

 

以上是关于求两个有序序列合并成新有序序列的中位数,求第k小数的主要内容,如果未能解决你的问题,请参考以下文章

归并排序法

归并排序和堆排序

归并排序--详细解释版

经典算法学习——归并排序

二路归并排序算法

归并排序