面试题30 最小的K个数

何海涛:《剑指Offer:名企面试官精讲典型编程题》:九度OJ

题目描述:

输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。

输入:

每个测试案例包括2行:

第一行为2个整数n,k(1<=n,k<=200000),表示数组的长度。

第二行包含n个整数,表示这n个数,数组中的数的范围是[0,1000 000 000]。

输出:

对应每个测试案例,输出最小的k个数,并按从小到大顺序打印。

样例输入:
8 4
4 5 1 6 2 7 3 8

样例输出:

1 2 3 4


代码:目前想到两种方法:  快排的改版 和 小堆,可惜最后一个实例 的时候 TLE ,不过可以尝试使用 红黑树 ,没有试过。。。。

快排:

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3.   
  4. void quick(int data[], int low, int high ,int k)  
  5. {  
  6.     int i = low, j = high, tmp = data[low];  
  7.   
  8.     if (low < high)  
  9.     {  
  10.         // if是随机一个 准点,那么与第一个交换在处理就是咯~  
  11.         // Swap(data[low], data[(low + high) / 2]); //将中间的这个数和第一个数交换   
  12.   
  13.         while (i < j)  
  14.         {  
  15.             while(i < j && data[j] >= tmp)    // 从右向左找第一个小于tmp的数,等于tmp跳过  
  16.             {  
  17.                 j--;    
  18.             }  
  19.             if(i < j)                        // 这个判断是需要的~   
  20.             {  
  21.                 data[i++] = data[j];  
  22.             }  
  23.               
  24.             while(i < j && data[i] < tmp) // 从左向右找第一个大于等于tmp的数  
  25.             {  
  26.                 i++;    
  27.             }  
  28.             if(i < j)   
  29.             {  
  30.                 data[j--] = data[i];  
  31.             }  
  32.         }  
  33.   
  34.         data[i] = tmp;                  // 原数据归位到中间  
  35.   
  36.         if( i == k )                    // 已经出处理了K个  
  37.         {  
  38.             return;  
  39.         }  
  40.   
  41.         quick(data, low, i - 1, k);     // 递归调用  
  42.   
  43.         if( i > k )                      // if左边的个数已经足够,那么右边的处理就可以省略了,因为左边已经包含K个数  
  44.         {  
  45.             return ;  
  46.         }  
  47.   
  48.         quick(data, i + 1, high, k);  
  49.   
  50.     }  
  51. }  
  52.   
  53. int main()  
  54. {  
  55.     int * data, i, n, k;  
  56.   
  57.     while( scanf("%d%d", &n, &k) != EOF )  
  58.     {  
  59.         data = ( int* )malloc( sizeofint ) * n );  
  60.         for( i = 0; i < n; i++ )  
  61.         {  
  62.             scanf("%d", &data[i]);  
  63.         }  
  64.   
  65.         quick( data, 0, n - 1, k );  
  66.   
  67.         for( i = 0; i < k; i++ )  
  68.         {  
  69.             printf("%d ", data[i]);  
  70.         }  
  71.   
  72.         printf("\n");  
  73.   
  74.         free( data );  
  75.     }  
  76.   
  77.     return 0;  
  78. }  


min heap:

  1. // 小根堆( 堆是完全二叉树,所以用数组可以! )   
  2.   
  3. #include <stdio.h>  
  4.   
  5. void swap( int *data, int *b )  
  6. {  
  7.      int t = *data;  
  8.      *data = *b;  
  9.      *b = t;  
  10. }  
  11.   
  12. void adjust_heap(int *data,int i,int n)  //调整堆   
  13. {  
  14.     int lc = 2 * i;       //i的左孩子节点序号   
  15.     int rc = 2 * i + 1;   //i的右孩子节点序号   
  16.     int min = i;              //临时变量   
  17.       
  18.     if( i <= n / 2 )       //如果i是叶节点就不用进行调整   
  19.     {  
  20.         if( lc <= n && data[lc] > data[min] )  
  21.         {  
  22.             min = lc;  
  23.         }      
  24.         if( rc <= n && data[rc] > data[min] )  
  25.         {  
  26.             min = rc;  
  27.         }  
  28.         if( min != i )  
  29.         {  
  30.             swap(&data[i],&data[min]);  
  31.             adjust_heap(data,min,n); //避免调整之后以min为父节点的子树不是堆   
  32.         }  
  33.     }          
  34. }  
  35.   
  36. void build_heap(int *data,int n)    //建立堆   
  37. {  
  38.     int i;  
  39.       
  40.     for( i = n / 2; i >= 1; i-- ) //非叶节点最大序号值为n/2   
  41.     {  
  42.         adjust_heap(data,i,n);      
  43.     }      
  44. }   
  45.   
  46. void sort_heap(int *data,int n)    //堆排序   
  47. {  
  48.     int i;  
  49.       
  50.     for( i = n; i >= 1; i-- )  
  51.     {  
  52.         swap(&data[1],&data[i]);           //交换堆顶和最后一个元素,即每次将剩余元素中的最大者放到最后面      
  53.         adjust_heap(data,1,i-1);      //重新调整堆顶节点成为大顶堆  
  54.     }  
  55. }   
  56.   
  57. int main(int argc, char *argv[])  
  58. {  
  59.     int data[200000];  
  60.     int n, k;  
  61.     int i;  
  62.     while( scanf("%d%d",&n, &k) != EOF )  
  63.     {  
  64.         for( i = 1; i <= n; i++ )  // 注意此处从 idx = 1 开始   
  65.         {  
  66.             scanf("%d", &data[i]);  
  67.         }  
  68.           
  69.         build_heap(data,n);  
  70.         sort_heap(data,n);  
  71.         /* 
  72.         for( i = 1; i <= n; i++ ) 
  73.         { 
  74.             printf("%d ", data[i]); 
  75.         } 
  76.         printf("\n"); 
  77.         */  
  78.         while( k > 1 )  
  79.         {  
  80.                k--;  
  81.                printf("%d ", data[1]);  
  82.                data[1] = data[n];  
  83.                n--;  
  84.                sort_heap(data,n);  
  85.         }  
  86.         printf("%d\n", data[1]);  
  87.     }  
  88.     return 0;  
  89. }  
 
貌似红黑可以解决超时,AVL也可以尝试,后期再说。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值