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