兩個有序數組中第k小的數字

已知兩個數組均爲有序的,找出第k小的數。

1、歸併排序,時間複雜度爲O(n)

2、二分查找

對於數組A 、 B , 如果 B[pb] < A[pa] && B[pb] > A[pa - 1], 那麼 B[pb] 一定是第 pa + pb + 1  小的數。比如數組A = {1, 8, 10, 20}, B = {5, 9, 22, 110},
pa = 2, pb = 1, 這時,(B[pb] = 9) < (A[pa] =10) && (B[pb] = 9) > (A[pa - 1] = 8) ,那麼,B[pb] = 9 一定是第 pa+pb+1 = 4 小的數。
換一句話說,如果我們要找第 k 小的數,那麼, pa + pb  = k - 1。

而且,B[pb] < A[pa] && B[pb] > A[pa - 1] 或者 A[pa] < B[pb] && A[pa] > B[pb - 1] 中的其中一個必須成立。 如果不成立, 我們需要移動pa 和 pb 的位置來使得其中的一個式子成立 。這是本題算法的本質。

假如第k大的數在a中,設置a[mid],那麼肯定有b[k-mid-1]<=a[mid]<=b[k-mid],這是由於a中已經有mid個元素<a[mid]了,

則b中肯定還有k-mid - 1個元素小於a[mid],所以我們判斷
若b[k-mid-2]<=a[mid]<=b[k-mid-1], 返回a[mid]

若a[mid] < b[k-mid-2] 說明a[mid]小於第k個元素值,a.low = a.mid + 1
若a[mid] > b[k-mid-1],說明a[mid]大於第k個元素值,a.high = a.mid - 1
結束條件爲a.low > a.high 如果未找到,則假設存在於b中,再判斷一次

int get_k_from_sorted_array(int* a, int* b, int low, int high, int k, int len)
{
    if(low > high)
        return -1;
    int mid = low + (high - low)/2;
    //a中元素個數小於k個,那麼k - 2 - mid就可能超出b的下標範圍
    if(k - 2 - mid >= len)
        return get_k_from_sorted_array(a, b, mid + 1, high, k, len);
    if(k - 1 - mid < len)
    {
        //判斷b數據中是否存在b[k-1-mid]
        if(a[mid] >= b[k - mid - 2] && a[mid] <= b[k - mid - 1])
            return a[mid];
    }
    else
    {
        if(a[mid] >= b[k - mid - 2])
            return a[mid];
    }
    if(a[mid] < b[k - mid - 2])
        return get_k_from_sorted_array(a, b, mid + 1, high, k, len);
    return get_k_from_sorted_array(a, b, low, mid - 1, k, len);
}
int _func(int* a, int a_len, int* b, int b_len, int k)
{
    int rst = 0;
    if(a_len + b_len + 2 < k)
        return -1;
    int p1 = a_len > k - 1 ? k - 1: a_len;
    int p2 = b_len > k - 1 ? k - 1: b_len;
    rst = get_k_from_sorted_array(a, b, 0, p1, k, 4);
    if(-1 == rst)
    {
        rst = get_k_from_sorted_array(b, a, 0, p2, k, 5);
    }
    return rst;
}
3、剪切法

判斷a[mid_a] 與 b[mid_b]的關係
 如果a[mida] < b[mid_b]
 1)k小於等於mida + midb + 1,那麼b數組從mid_b開始就沒有用了,縮小b的搜索範圍
 2)k大於mida + midb + 1, 那麼a數組從low到mid_a開始就沒用了,縮小a的搜索範圍
 3)終止條件是 a搜索完 返回b中元素或者相反

int get_k_from_sorted_array2(int* a, int*b, int la, int ha, int lb, int hb, int k)
{
    if(la > ha)
        return b[lb + k - 1];
    if(lb > hb)
        return a[la + k - 1];
    int mida = (la + ha)>>1;
    int midb = (lb + hb)>>1;
    int num = mida- la + midb - lb + 1;
    cout<<la<<" "<<ha<<" "<<lb<<" "<<hb<<" "<<num<<" "<<a[mida]<<" "<<b[midb]<<endl;
    
    if(a[mida] <= b[midb])
    {
        if(k <= num)
            return get_k_from_sorted_array2(a, b, la, ha, lb, midb - 1, k);
        else
            return get_k_from_sorted_array2(a, b, mida + 1, ha, lb, hb, k - (mida - la + 1));
    }
    else
    {
        if(k <= num)
            return get_k_from_sorted_array2(a, b, la, mida - 1, lb, hb, k);
        else
            return get_k_from_sorted_array2(a, b, la, ha, midb + 1, hb, k - (midb - lb + 1));
    }
}
int _func2(int* a, int a_len, int* b, int b_len, int k)
{
    int rst = 0;
    if(a_len + b_len < k)
        return -1;
    int p1 = a_len > k ? k : a_len;
    int p2 = b_len > k ? k : b_len;
    cout<<p1<<" "<<p2<<endl;
    rst = get_k_from_sorted_array2(a, b, 0, p1 - 1, 0, p2 - 1, k);
    return rst;
}
參考文獻:http://www.cnblogs.com/buptLizer/archive/2012/03/31/2427579.html



發佈了69 篇原創文章 · 獲贊 8 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章