尋找第k大的數(shù)

目錄:
1、引子
2、排序解決法
3、類快排解法
4、最小堆解法

1、引子

日常編碼中,常見遇到這樣的問題,“尋找最大的數(shù)”,此問題非常容易,可暴力直接遍歷找出,也可使用分冶策略找出最大值(詳見分冶算法)。

本文中需要尋找第k大的數(shù),筆者目前想到3個(gè)方法可解決它。

2、排序解決法

如果是一個(gè)有序數(shù)組,那么尋找第k的大數(shù)則相當(dāng)簡(jiǎn)單了,且效率為1。數(shù)組排序算法中相對(duì)較優(yōu)的算法為快速排序,效率為N*lgN,將數(shù)組從到到小排列,第k大的數(shù)則為array[k-1]。

快排的思想為,從數(shù)組中取任意一個(gè)值key,將大于key的值放在key右邊,小于key的值放在key左邊。key的左邊和右邊則都是有序的了,然后遞歸key左邊的子數(shù)組和key右邊的子數(shù)組,直到每個(gè)子數(shù)組長度為1,此時(shí),整個(gè)數(shù)組均有序了。

代碼如下

public static int partition(int[] array, int left, int right) {
    int k = array[left];
    int i = left;
    int j = right;
    while (j > i) {
        while (array[j] < k && j > i) {
            j--;
        }
        if (j > i) {
            array[i] = array[j];
            i++;
        }
        while (array[i] > k && j > i) {
            i++;
        }
        if (j > i) {
            array[j] = array[i];
            j--;
        }
    }
    array[i] = k;
    return i;
}

public static void quickSort(int[] array, int left, int right) {
    if (left >= right) {
        return;
    }
    int i = partition(array, left, right);
    quickSort(array, left, i - 1);
    quickSort(array, i + 1, right);
}

本文中快排略有差異,是按從大到小順序排列。
快排的partition算法有兩種寫法,具體可查看快速排序及主定理。此解法效率為N*lgN

3、類快排解法

由于只要求找出第k大的數(shù),沒必要將數(shù)組中所有值都排序。

快排中的partition算法,返回key在數(shù)組中的位置,如果key的位置正好等于k-1,那么問題則得到解決,如果key的位置不等于k-1,可使用遞歸查找對(duì)應(yīng)子數(shù)組。直到key的位置等于k-1,則找對(duì)問題的解。

public static int findK(int[] array, int left, int right, int k) {
    int i = partition(array, left, right);
    if (i == k - 1) {
        return array[k - 1];
    } else if (i > k - 1) {
        return findK(array, left, i - 1, k);
    } else if (i < k - 1) {
        return findK(array, i + 1, right, k);
    }
    return 0;
}

此解法的效率值為N*lgK,由于K是常數(shù),所以此解法效率值為N,優(yōu)于排序解法

4、最小堆解法

最小堆是一種特殊的數(shù)組結(jié)構(gòu),它實(shí)質(zhì)是一個(gè)完全二叉樹,且樹中子節(jié)點(diǎn)的值均大于父節(jié)點(diǎn)的值,詳見 堆排序及優(yōu)先隊(duì)列。

考慮到只需要找到第k大的數(shù),構(gòu)造一個(gè)大小為k的最小堆,堆中根節(jié)點(diǎn)為最小值。如果數(shù)組中最大的幾個(gè)數(shù)均在堆中,那么堆中根節(jié)點(diǎn)的值就是問題的解。

構(gòu)造最小堆

public static void maxHeapify(int[] array, int size, int i) {
    int left = 2 * i + 1;
    int right = 2 * i + 2;
    int small = i;
    if (left < size) {
        if (array[small] > array[left]) {
            small = left;
        }
    }
    if (right < size) {
        if (array[small] > array[right]) {
            small = right;
        }
    }
    if (small != i) {
        int temp = array[small];
        array[small] = array[i];
        array[i] = temp;
        maxHeapify(array, size, small);
    }
}

public static void buildHeap(int[] array, int size) {
    for (int i = size - 1; i >= 0; i--) {
        maxHeapify(array, size, i);
    }
}

最小堆已構(gòu)造完成,將數(shù)組中剩余的值與根節(jié)點(diǎn)相比,大于根節(jié)點(diǎn)的值則將根節(jié)點(diǎn)的值與之交換,同時(shí)維護(hù)最小堆的特性,遍歷結(jié)束,則根結(jié)點(diǎn)即為問題的解。

public static int findKByHeap(int[] array, int k) {
    buildHeap(array, k);
    for (int i = k + 1; i < array.length; i++) {
        if (array[i] > array[0]) {
            int temp = array[i];
            array[i] = array[0];
            array[0] = temp;
            maxHeapify(array, k, 0);
        }
    }
    return array[0];
}

代碼地址:https://github.com/okunu/DataStructure ,歡迎訪問本人的github

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 概述 排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序,而外部排序是因排序的數(shù)據(jù)很大,一次不能容納全部...
    蟻前閱讀 5,297評(píng)論 0 52
  • 1 序 2016年6月25日夜,帝都,天下著大雨,拖著行李箱和同學(xué)在校門口照了最后一張合照,搬離寢室打車去了提前租...
    RichardJieChen閱讀 5,372評(píng)論 0 12
  • 概述:排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序,而外部排序是因排序的數(shù)據(jù)很大,一次不能容納全部...
    每天刷兩次牙閱讀 3,819評(píng)論 0 15
  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 將一個(gè)記錄插入到已排序好...
    依依玖玥閱讀 1,347評(píng)論 0 2
  • 對(duì)著電腦一直整理專業(yè)課整理的我眼睛都要瞎了,所以今天就跟大家分享一首詩吧,再對(duì)著電腦就真的快一口血噴出來了。 是汪...
    云時(shí)之間閱讀 583評(píng)論 2 1

友情鏈接更多精彩內(nèi)容