<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    莊周夢(mèng)蝶

    生活、程序、未來(lái)
       :: 首頁(yè) ::  ::  :: 聚合  :: 管理
       
        javaeye的一個(gè)帖子介紹一道面試題,取數(shù)組的最大元素和前n個(gè)大元素,取最大元素很簡(jiǎn)單,遍歷即可。取前N大元素,可以利用排序,最簡(jiǎn)單的實(shí)現(xiàn):

        public static int[] findTopNValues(int[] anyOldOrderValues, int n) {
            Arrays.sort(anyOldOrderValues);
            
    int[] result = new int[n];
            System.arraycopy(anyOldOrderValues, anyOldOrderValues.length 
    - n,
                    result, 
    0, n);
            
    return result;
        }
       
         Arrays.sort(int[])使用的是快排,平均的時(shí)間復(fù)雜度是O( n lg(n)),在一般情況下已經(jīng)足夠好。那么有沒(méi)有平均情況下O(n)復(fù)雜度的算法?這個(gè)還是有的,這道題目其實(shí)是選擇算法的變形,選擇一個(gè)數(shù)組中的第n大元素,可以采用類(lèi)似快排的方式劃分?jǐn)?shù)組,然后只要在一個(gè)子段做遞歸查找就可以,平均狀況下可以做到O(n)的時(shí)間復(fù)雜度,對(duì)于這道題來(lái)說(shuō)稍微變形下算法即可解決:

        /**
         * 求數(shù)組的前n個(gè)元素
         * 
         * 
    @param anyOldOrderValues
         * 
    @param n
         * 
    @return
         
    */
        
    public static int[] findTopNValues(int[] anyOldOrderValues, int n) {
            
    int[] result = new int[n];
            findTopNValues(anyOldOrderValues, 
    0, anyOldOrderValues.length - 1, n,
                    n, result);
            
    return result;
        }

        
    public static final void findTopNValues(int[] a, int p, int r, int i,
                
    int n, int[] result) {
            
    // 全部取到,直接返回
            if (i == 0)
                
    return;
            
    // 只剩一個(gè)元素,拷貝到目標(biāo)數(shù)組
            if (p == r) {
                System.arraycopy(a, p, result, n 
    - i, i);
                
    return;
            }
            
    int len = r - p + 1;
            
    if (i > len || i < 0)
                
    throw new IllegalArgumentException();
            
    // if (len < 7) {
            
    // Arrays.sort(a, p, r+1);
            
    // System.arraycopy(a, r - i+1 , result, n - i, i);
            
    // return;
            
    // }

            
    // 劃分
            int q = medPartition(a, p, r);
            
    // 計(jì)算右子段長(zhǎng)度
            int k = r - q + 1;
            
    // 右子段長(zhǎng)度恰好等于i
            if (i == k) {
                
    // 拷貝右子段到結(jié)果數(shù)組,返回
                System.arraycopy(a, q, result, n - i, i);
                
    return;
            } 
    else if (k > i) {
                
    // 右子段比i長(zhǎng),遞歸到右子段求前i個(gè)元素
                findTopNValues(a, q + 1, r, i, n, result);
            } 
    else {
                
    // 右子段比i短,拷貝右子段到結(jié)果數(shù)組,遞歸左子段求前i-k個(gè)元素
                System.arraycopy(a, q, result, n - i, k);
                findTopNValues(a, p, q 
    - 1, i - k, n, result);
            }
        }

        
    public static int medPartition(int x[], int p, int r) {
            
    int len = r - p + 1;
            
    int m = p + (len >> 1);
            
    if (len > 7) {
                
    int l = p;
                
    int n = r;
                
    if (len > 40) { // Big arrays, pseudomedian of 9
                    int s = len / 8;
                    l 
    = med3(x, l, l + s, l + 2 * s);
                    m 
    = med3(x, m - s, m, m + s);
                    n 
    = med3(x, n - 2 * s, n - s, n);
                }
                m 
    = med3(x, l, m, n); // Mid-size, med of 3
            }
            
    if (m != r) {
                
    int temp = x[m];
                x[m] 
    = x[r];
                x[r] 
    = temp;
            }
            
    return partition(x, p, r);
        }

        
    private static int med3(int x[], int a, int b, int c) {
            
    return x[a] < x[b] ? (x[b] < x[c] ? b : x[a] < x[c] ? c : a)
                    : x[b] 
    > x[c] ? b : x[a] > x[c] ? c : a;
        }

        
    public static void swap(int[] a, int i, int j) {
            
    int temp = a[i];
            a[i] 
    = a[j];
            a[j] 
    = temp;
        }

        
    public static int partition(int a[], int p, int r) {
            
    int x = a[r];
            
    int m = p - 1;
            
    int j = r;
            
    while (true) {
                
    do {
                    j
    --;
                } 
    while (j>=p&&a[j] > x);
                
    do {
                    m
    ++;
                } 
    while (a[m] < x);
                
                
    if (j < m)
                    
    break;
                swap(a, m, j);
            }
            swap(a, r, j 
    + 1);
            
    return j + 1;
        }
     選擇算法還有最壞情況下O(n)復(fù)雜度的實(shí)現(xiàn),有興趣可以讀算法導(dǎo)論和維基百科。題外,我測(cè)試了下這兩個(gè)實(shí)現(xiàn),在我的機(jī)器上大概有2倍多的差距,還是很明顯。


    評(píng)論

    # re: 一道面試題注記  回復(fù)  更多評(píng)論   

    2010-11-01 00:26 by yangwm
    你給出的算法, 源碼不全, 理解不了。

    我也寫(xiě)了一個(gè),可以看我的博客《最大N算法(前一版本的改進(jìn))》:
    MaxNAlgorithm比最簡(jiǎn)單的排序后取最大的n位, 效率高十陪以上(當(dāng)然需排序結(jié)果也要有足夠大才行; 測(cè)試結(jié)果只是個(gè)比較而已,因?yàn)関m沒(méi)有先預(yù)熱以及相應(yīng)參數(shù)配置)。

    # re: 一道面試題注記  回復(fù)  更多評(píng)論   

    2010-11-01 09:28 by denniis
    @yangwm
    這源碼很全了吧……

    # re: 一道面試題注記  回復(fù)  更多評(píng)論   

    2010-11-01 09:35 by dennis
    @yangwm
    不好意思,是遺漏來(lái)med3這個(gè)方法,補(bǔ)上。這個(gè)算法跟快排的分治算法是一樣的,快排可以用的那些優(yōu)化手段也可以在這里用上。

    # re: 一道面試題注記  回復(fù)  更多評(píng)論   

    2010-11-01 09:41 by dennis
    @yangwm
    我測(cè)試下我的實(shí)現(xiàn),大概比你的那個(gè)實(shí)現(xiàn)還快上4-5倍,不過(guò)你的實(shí)現(xiàn)多了一個(gè)box/unbox的開(kāi)銷(xiāo),本身就不公平。當(dāng)然,我上面提到來(lái),我的這個(gè)實(shí)現(xiàn)還有改進(jìn)的空間:改進(jìn)劃分算法,當(dāng)子段小的時(shí)候不做遞歸而做排序等等。

    另外就是我的結(jié)果集合是沒(méi)有排序的,你的測(cè)試程序只輸出前10個(gè),因此看起來(lái)結(jié)果不同,將結(jié)果全部排序并輸出即可驗(yàn)證我的程序也是正確的。

    # re: 一道面試題注記  回復(fù)  更多評(píng)論   

    2010-11-01 22:13 by yangwm
    我的那個(gè)算法改為基本類(lèi)型版的吧。
    同時(shí)與你的你的算法做了一下對(duì)比測(cè)試。
    實(shí)現(xiàn)比你的還快一些。

    # re: 一道面試題注記  回復(fù)  更多評(píng)論   

    2010-11-01 22:15 by yangwm
    見(jiàn)http://blog.csdn.net/yang_net/archive/2010/11/01/5978488.aspx

    # re: 一道面試題注記[未登錄](méi)  回復(fù)  更多評(píng)論   

    2010-11-01 23:24 by dennis
    @yangwm

    說(shuō)快或者說(shuō)慢,總有個(gè)前提,以你的代碼為例,取前10個(gè),是你的會(huì)快一些,而取前10000個(gè),卻是我的快很多。此外,優(yōu)秀的算法還需要考慮其他情況,比如數(shù)組的重復(fù)元素比較多,比如數(shù)組已經(jīng)排序等等。我改進(jìn)了一下劃分算法,有興趣可以再測(cè)試看看。

    # re: 一道面試題注記  回復(fù)  更多評(píng)論   

    2010-11-01 23:42 by dennis
    @yangwm
    1000萬(wàn)取前10萬(wàn)個(gè),你的實(shí)現(xiàn)性能下降很驚人,比較奇怪。而我的這個(gè)實(shí)現(xiàn)可以在任意維度下維持一個(gè)優(yōu)秀的性能,包括各種特殊情況:數(shù)組已經(jīng)排序、數(shù)組重復(fù)元素非常多等。
    主站蜘蛛池模板: 亚洲日本韩国在线| 亚洲av永久无码制服河南实里| 中文字幕第13亚洲另类| 亚洲国产精品美女| 免费人成大片在线观看播放| 一级毛片aaaaaa免费看| 国产高清免费观看| 久久精品国产亚洲AV麻豆不卡| 两个人看www免费视频| 四色在线精品免费观看| 三上悠亚亚洲一区高清| 一级做a爰性色毛片免费| 人妻视频一区二区三区免费| 亚洲国产精华液网站w| 色一情一乱一伦一视频免费看| 59pao成国产成视频永久免费| 久久久久亚洲av毛片大 | 国产成年无码久久久免费| 性做久久久久免费观看| 亚洲天堂一区在线| 免费观看的毛片大全| 亚洲精品~无码抽插| 亚洲AV色欲色欲WWW| 2019中文字幕在线电影免费| 亚洲精品中文字幕无乱码| 中国一级全黄的免费观看| 国产最新凸凹视频免费| 美女啪啪网站又黄又免费| 亚洲日本在线观看视频| 国产在线观看免费av站| 亚洲av日韩av高潮潮喷无码| 未满十八私人高清免费影院| 国产精品极品美女免费观看| 四虎影视久久久免费观看| 亚洲精品乱码久久久久久中文字幕| 久久免费观看国产精品| 亚洲国产第一站精品蜜芽| 18观看免费永久视频| 美女视频黄免费亚洲| 久久免费看黄a级毛片| 亚洲日本乱码卡2卡3卡新区|