寻找第 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阅读 787评论 0 3
  • 准备去学英语了,内心来说是我自己自愿的,其实我不怕苦,虽然可能真的实施的时候还是会觉得辛苦,但是还是选择去。可能是...
    素年不安阅读 248评论 0 0