k-选取问题

一、k-选取问题:
给定任意一个可比较的序列,从中找出第k个元素(k从0开始,默认是从小到大的次序)的问题称为k-选取(k-selection)。
k-选取问题有两种退化的情况:
1、0-选取问题即是找出序列的最小值问题。
2、(length-1)-选取问题即是找出序列的最大值问题。
以上两中问题都有最优解,都可以在线性的时间复杂度内求解。

k-选取问题的另一个常见的问题是中位数问题:
严格来说:
1、如果序列的长度为奇数,其中位数为ary[length/2]
2、如果序列的长度为偶素,其中位数为(ary[length/2-1]+ary[length/2])/2

但是可以稍作简化,统一规定序列中位数为索引为length/2的元素。

二、k-选取问题的一般解:

    //此非递归的版本实际为减治思想
    public static int kSelection(int[] ary,int k){
        int length = ary.length;
        if (k < 0 || k > length-1) {return -1;}//k值不在范围内
        int index,low = 0,high = length-1;
        while(true){
            index = position(ary, low, high);
            if (index == k) {break;}//命中,返回
            if (index < k) {//k必然会在index+1和high之间
                low = index+1;
            }else {//k必然会在low1和index-1之间
                high = index-1;
            }
        }
        return index;
    }

三、主流数问题

除此之外,还有一个与之稍有关联的问题时序列主流数问题:
若序列中有一半以上的值(此处定义为严格大于一半)同为m,这该值m称为该序列的主流数。

不难发现,如果某序列有主流数m,则经过排序后,ary[length/2]必定等于该序列的主流数。

    public static boolean hasMajority(int[] ary){
        int length = ary.length;
        int index = kSelection(ary,length/2);//k为length/2
        int count = 0;
        for (int i = 0; i < length; i++) {
            if (ary[i] == ary[index]) {
                count++;
            }
        }
        return count > length/2;//如果存在主流数,ary[index]重复次数必然大于length/2
    }

 

posted @ 2017-09-20 23:23  Qcer  阅读(333)  评论(0编辑  收藏  举报