• 17082 两个有序数序列中找第k小(优先做) O(logn)


    17082 两个有序数序列中找第k小(优先做)

    时间限制:1000MS  内存限制:65535K
    提交次数:0 通过次数:0

    题型: 编程题   语言: G++;GCC;VC

     

    Description

    已知两个已经排好序(非减序)的序列X和Y,其中X的长度为m,Y长度为n,
    现在请你用分治算法,找出X和Y的第k小的数,算法时间复杂度为O(max{logm, logn})。
    
    此题请勿采用将序列X和Y合并找第k小的O(m+n)的一般方法,要充分利用X和Y已经排好序的这一特性。
    




    输入格式

    第一行有三个数,分别是长度m、长度n和k,中间空格相连(1<=m,n<=100000; 1<=k<=m+n)。
    第二行m个数分别是非减序的序列X。第三行n个数分别是非减序的序列Y。



    输出格式

    序列X和Y的第k小的数。



     

    输入样例

    5 6 7
    1 8 12 12 21 
    4 12 20 22 26 31



     

    输出样例

    20



     

    提示

    假设:X序列为X[xBeg...xEnd],而Y序列为Y[yBeg...yEnd]。
    
    将序列X和Y都均分2段,即取X序列中间位置为 xMid (xMid = xBeg+(xEnd-xBeg)/2),也同理取序列Y中间位置为yMid。
    比较X[xMid]和Y[yMid]的大小,此时记录X左段和Y左段元素个数合计为halfLen,即halfLen = xMid-xBeg+yMid-yBeg+2。
    
    1. 当X[xMid] < Y[yMid]时,在合并的数组中,原X[xBeg...xMid]所有元素一定在Y[yMid]的左侧,
       (1) 若k < halfLen,则此时第k大的元素一定不会大于Y[yMid]这个元素,
             故以后没有必要搜索 Y[yMid...yEnd]这些元素,可弃Y后半段数据。
             此时只需递归的对X序列+Y序列的前半段,去搜索第k小的数。
    
       (2) 若k >= halfLen,则此时第k大的元素一定不会小于X[xMid]这个元素,
             故以后没有必要搜索 X[xBeg...xMid]这些元素,可弃X前半段数据。
             此时只需递归的对X序列的后半段+Y序列,去搜索第 k-(xMid-xBeg+1)小的数。
    
    2. 当X[xMid] >= Y[yMid]时,在合并的数组中,原Y[yBeg...yMid]的所有元素一定在X[xMid]的左侧,
       (1) 若k < halfLen,则此时第k大的元素一定不会大于X[xMid]这个元素,
             故以后没有必要搜索 X[xMid...xEnd]这些元素,可弃X后半段数据。
             此时只需递归的对X序列的前半段+Y序列,去搜索第k小的数。
    
       (2) 若k >= halfLen,则此时第k大的元素一定不会小于Y[yMid]这个元素,
             故以后没有必要搜索 Y[yBeg...yMid]这些元素,可弃Y前半段数据。
             此时只需递归的对X序列+Y序列的后半段,去搜索第 k-(yMid-yBeg+1)小的数。
    
    递归的边界,如何来写?
    1) if (xBeg > xEnd) return Y[yBeg + k - 1];  //X序列为空时,直接返回Y序列的第k小元素。
    2) if (yBeg > yEnd) return X[xBeg + k - 1];  //Y序列为空时,直接返回X序列的第k小元素。
    
    
    效率分析:
    
    T(m,n)表示对长度为m的有序的X序列和长度为n的有序的Y序列,搜索第k小元素的复杂度。
    T(m,n)=1   m=0或n=0
    T(m,n) <= max{T(m/2,n), T(m,n/2)} + O(1)
    
    则T(m,n) = O(max{logm, logn})
    
    



     

    作者

     zhengchan

    首先,如果a数组取a[k/2]那个值,b数组需要取b[k - k/2]那个值,这样使得两者加起来是k个,然后,如果a[k/2] > b[k - k/2],那么b[k-k/2]肯定不会是答案,又因为递增,所以b[k-k/2]前面的可以不用考虑了,直接把这部分pass掉。同理其他。

    注意的是,每次都需要在比较短的那个数组里面取值,再去长度大的那个数组里面找k - k/2

    #include <stdio.h>
    #include <stdlib.h>
    #include <algorithm>
    #include <iostream>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    const int maxn = 1e5 + 20;
    int a[maxn], b[maxn];
    
    int findkthMin(int aBe, int aEn, int bBe, int bEn, int k) {
        if (aEn < aBe) return b[bBe + k - 1];
        if (bEn < bBe) return a[aBe + k - 1];
        if (k == 1) return min(a[aBe], b[bBe]);
        if (aEn - aBe < bEn - bBe) {
            int asel = min(k / 2, aEn - aBe + 1), bsel = k - asel;
            int posa = aBe + asel - 1, posb = bBe + bsel - 1;
            if (a[posa] == b[posb]) return a[posa];
            if (a[posa] < b[posb]) return findkthMin(posa + 1, aEn, bBe, bEn, k - asel);
            if (a[posa] > b[posb]) return findkthMin(aBe, aEn, posb + 1, bEn, k - bsel);
        } else {
            int bsel = min(k / 2, bEn - bBe + 1), asel = k - bsel;
            int posa = aBe + asel - 1, posb = bBe + bsel - 1;
            if (a[posa] == b[posb]) return a[posa];
            if (a[posa] < b[posb]) return findkthMin(posa + 1, aEn, bBe, bEn, k - asel);
            if (a[posa] > b[posb]) return findkthMin(aBe, aEn, posb + 1, bEn, k - bsel);
        }
    }
    
    void work() {
        int n, m, k;
        cin >> n >> m >> k;
        for (int i = 1; i <= n; ++i) cin >> a[i];
        for (int j = 1; j <= m; ++j) cin >> b[j];
    //    printf("%d
    ", find_kth(a, n, b, m, k));
        printf("%d
    ", findkthMin(1, n, 1, m, k));
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        work();
        return 0;
    }
  • 相关阅读:
    从下拉菜单设计细节看Amazon对用户体验的把握
    单行省略号纯css解决方案
    2013年度最新整理45个div+css兼容性问题与解决方案
    20个非常绚丽的 CSS3 特性应用演示
    分享30个最佳 jQuery Lightbox 效果插件【只收藏经典】
    如何让网站被快速收录?
    About FAR HTML
    前端工具
    Web设计师必备的10款最佳排版工具
    清除浮动解决方案
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/7890062.html
Copyright © 2020-2023  润新知