尋找第 k 小元素-分治法

問題

對一個已經序列A[1,...,n],如何尋找其第k小的元素?

算法

使它在O(n)的時間復雜度內解決

code

package wentao.algorithm.ex;

import java.util.Arrays;

public class FindTheLastKMinNum {

    public static void main(String[] args) {
        int[] A = { 8, 33, 17, 51, 57, 49, 35, 11, 25, 37, 14, 3, 2, 13, 52,
                12, 6, 29, 32, 54, 5, 16, 22, 23, 7 };
        int K = 18;
        int theLastKMin = findTheLastKMinNum(A, 0, A.length - 1, K);
        System.out.println("第" + K + "小的數是:" + theLastKMin);
    }

    /**
     * 
    * 方法名: findTheLastKMinNum
    * 方法作用: 分治法求第k小值
    * 創建人:WENTAO Wan
    * 創建時間:2016年4月4日 下午11:15:39   
    * @param @param A
    * @param @param low
    * @param @param high
    * @param @param K
    * @param @return    
    * 返回值類型: int    
    * @throws
     */
    public static int findTheLastKMinNum(int[] A, int low, int high, int K) {

        // 設置閾值
        int p = high - low + 1;
        if (p < 6) {

            // 這里要注意新分配的空間 q+1造成干擾,不能直接Sort(A)
            Arrays.sort(A, low, p);
            return A[K - 1];
        } else {

            // 分為五段
            int q = p / 5;
            int remainder = p - q * 5;

            // 每段排序并把中項存入mid
            int[] mid = new int[q + 1];
            for (int i = 0; i < q; i++) {
                Arrays.sort(A, 5 * i, (i + 1) * 5);
                mid[i] = A[i * 5 + 2]; // low
            }

            // 除不盡5之后的分為一段并找出中項存入mid
            if (remainder > 0) {
                Arrays.sort(A, 5 * q, 5 * q + remainder);
                mid[q] = A[q * 5 + (remainder + 1) / 2 - 1];
            }

            // 中項集合的中項
            int mm = findTheLastKMinNum(mid, 0, q - 1, (q + 1) / 2);

            int[] A1 = new int[p];
            int[] A2 = new int[p];
            int[] A3 = new int[p];
            int lenA1 = 0, lenA2 = 0, lenA3 = 0;

            // 分別與中項比較,分為新的三段
            for (int i = low; i <= high; i++) {
                if (A[i] < mm) {
                    A1[lenA1++] = A[i];
                } else if (A[i] == mm) {
                    A2[lenA2++] = A[i];
                } else if (A[i] > mm) {
                    A3[lenA3++] = A[i];
                }
            }

            // 將三段的長度與K比較判斷K的位置并遞歸
            int theLastKMin = 0;
            if (lenA1 >= K) {
                theLastKMin = findTheLastKMinNum(A1, 0, lenA1 - 1, K);
            } else if (lenA2 + lenA1 < K) {
                theLastKMin = findTheLastKMinNum(A3, 0, lenA3 - 1, K - lenA1
                        - lenA2);
            } else if (lenA1 + lenA2 >= K) {
                theLastKMin = mm;
            }

            return theLastKMin;
        }

    }
}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 背景 一年多以前我在知乎上答了有關LeetCode的問題, 分享了一些自己做題目的經驗。 張土汪:刷leetcod...
    土汪閱讀 12,769評論 0 33
  • 總結一下常見的排序算法。 排序分內排序和外排序。內排序:指在排序期間數據對象全部存放在內存的排序。外排序:指在排序...
    jiangliang閱讀 1,375評論 0 1
  • 我的理想就是: “我的理想不再是理想。” 這是歌手趙雷參加比賽,演唱歌曲《理想》前說的一句話。 雖然只是簡單的幾個...
    梅芳的行影記閱讀 1,002評論 0 3
  • 我們現在大部分服務器其實是在linux下運行的,所以windows其實大多數是本地配合開發調試使用,當然本小白也是...
    伊凡丶real閱讀 786評論 0 3
  • 準備去學英語了,內心來說是我自己自愿的,其實我不怕苦,雖然可能真的實施的時候還是會覺得辛苦,但是還是選擇去。可能是...
    素年不安閱讀 248評論 0 0