k-选取问题

时间:2022-06-28 19:55:26

一、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
}