在面试中碰到求数组中第K小的数,(或者最小的的K个数)。
最直观的方法是排序之后,选择数组A的元素A[K-1]; 以快速排序为例,排序的时间复杂度为O(NlogN), 选择元素的时间为O(1)。
如果允许使用额外空间,则排序算法可以使使用时间复杂度为O(N)的基数排序。
如果时间复杂度要O(N), 不使用额外空间的话,可以借用快速排序中partition函数来达到想要的结果。
思路是:
在经过partion之后,会得到一个位置(索引)position, 该位置左边的元素都小于position位置的值,右边的都大。
1, 当 postion == K -1时, 该位置元素为所求
2, 当postion < K - 1时,说明应该去postion的右边去找
3, 否则,去左边找
下边来一个栗子:
求自定类型元素序列的中位数
本题要求实现一个函数,求N
个集合元素A[]
的中位数,即序列中第⌈N/2⌉大的元素。其中集合元素的类型为自定义的ElementType
。
函数接口定义:
ElementType Median( ElementType A[], int N );
其中给定集合元素存放在数组A[]
中,正整数N
是数组元素个数。该函数须返回N
个A[]
元素的中位数,其值也必须是ElementType
类型。
裁判测试程序样例:
#include <stdio.h>
#define MAXN 10
typedef float ElementType;
ElementType Median( ElementType A[], int N );
int main ()
{
ElementType A[MAXN];
int N, i;
scanf("%d", &N);
for ( i=0; i<N; i++ )
scanf("%f", &A[i]);
printf("%.2f\n", Median(A, N));
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
3
12.3 34 -5
输出样例:
12.30
解答:
注意事项: 根据题目对中位数的定义, 在数据量为偶数的时候, 我们需要的是中间两个数中右边的那一个,而不是两个元素的中指
代码:
#include <stdio.h>
#define MAXN 10
typedef float ElementType;
ElementType Median(ElementType A[], int N);
int main(){
ElementType A[MAXN];
int N, i;
scanf("%d", &N);
for(i=0; i<N; i++)
scanf("%f",&A[i]);
printf("%.2f\n", Median(A,N));
// printf("Test:\n");
// for(int i = 0; i < N; ++i){
// printf("%f ", A[i]);
// }
return 0;
}
void swap(ElementType A[], int i, int j){
// printf("Swaped! ");
ElementType temp = A[i];
A[i] = A[j];
A[j] = temp;
}
int partition(ElementType A[], int N, int left, int right){
// printf("reached! %d %d ", left, right);
ElementType pivot = A[right];
int index = left - 1;
for(int i = left; i < right; ++i){
if(A[i] < pivot) swap(A, ++index, i);
}
swap(A, ++index, right);
return index;
}
// 查找N个元素中的第K个小的元素(来自编程珠玑)
ElementType Median(ElementType A[], int N){
// printf("reached! ");
int position = -1, left = 0, right = N - 1;
int target = N / 2;
// if(N % 2 == 0) --target;
// if(position == target) return A[target];
while(1){
if (position < target) {
left = position + 1;
position = partition(A, N, left, right);
}
else if(position > target){
right = position - 1;
position = partition(A, N, left, right);
}
else {
// printf("position: %d ", position);
return A[position];
// break;
// return position;
}
}
}