【29】求无序序列中最小k个数

题目:给定一个无序序列和一个数k,求最小k个数(不要求数字有序)

分析:

方案一:最朴素的方法是利用快速排序,然后直接输出最小k个数,时间复杂度为O(nlogn)

方案二:利用快速排序的partition函数的性质,根据基准的性质,每次可以把序列分成两个部分,左边序列全部小于等于基准的值,右边序列全部大于等于序列的值。

              只要找到基准的位置为刚好为第k的位置,则序列前面即为最小k个数。和找第k大的数其实是一个性质的,时间复杂度都是O(n)。

              时间复杂度的证明:

              1. 假设总的元素个数有n个,则

                  第一次枚举n个数

                  第二次枚举n/2

                  第三次枚举n/4

                  ...................1

              2. 则总的时间为n+n/2+n/4+....+1 <= 2n,因此时间复杂度为O(n)

举例:假设序列为0 9 -1 6 7 3 5,最小k个数为-1 0 3

实例代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

//Partition函数
int Partition(int *arrNum, int l, int r){
     //数据不合法
	 if(arrNum == NULL || l > r){
         return -1;
     }
     int mid = (l+r)>>1;
     swap(arrNum[mid], arrNum[r]);
     int leftSeqIndex = l;
     //扫描
	 for(int i = l; i < r; i++){
	     if(arrNum[i] < arrNum[r]){
             if(i > leftSeqIndex){
  			     swap(arrNum[i], arrNum[leftSeqIndex]);
      		 }
      		 ++leftSeqIndex;
         }
     }
     swap(arrNum[leftSeqIndex], arrNum[r]);
     return leftSeqIndex;
} 

//输出最小k个数
void OutputMinKNumber(int *arrNum, int k){
	 for(int i = 0; i < k; i++){
	     cout<<arrNum[i]<<" ";
	 }
	 cout<<endl;
} 

//得到最小k个数
void GetMinKNumber(int *arrNum, int n, int k){
	 //数据不合法
	 if(arrNum == NULL || n <= 0 || k <= 0 || k > n){
        return;
	 }
	 int l = 0;
	 int r = n-1;
	 while(l <= r){
	     int index = Partition(arrNum, l, r);
	     if(index == -1){
       	     return;
		 }
	     if(index+1 == k){
			 OutputMinKNumber(arrNum, k);
			 return;
         }
         else if(index+1 > k){ //左边序列查找
		     r = index-1;
		 }
 	     else{
	         l = index+1;
		 }
	 }
} 

int main(){
    int arrNum[] = {0,9,-1,6,7,3,5};
    GetMinKNumber(arrNum, 7, 3);

    return 0;
}
/*
输出
-1 0 3
*/
时间: 2024-07-31 22:28:12

【29】求无序序列中最小k个数的相关文章

c语言-C语言 给定一个整数序列和一个数k,求这个序列中第k小的数。

问题描述 C语言 给定一个整数序列和一个数k,求这个序列中第k小的数. C语言 给定一个整数序列和一个数k,求这个序列中第k小的数. 我的程序 #include<stdio.h> int n[10000]; void Nok() { int i=0,j=0,t,k,q=0; char c; scanf("%d",&n[i++]); c=getchar(); while(c!='n') { scanf("%d",&n[i++]); c=ge

求一个序列中,第k个数

//求一个序列中,第k个数 1.排序,输出a[k-1]冒泡for(i=1;i<=n-1;i++)//控制循环次数 for(j=0;j<=n-i-1;j++)//不是n-i+1 if(a[i]>a[i+1]]) 交换,每排一次最大的移到最后 定位选择排序for(i=0;i<n-1;i++)//控制循环次数 for(j=i+1;j<n;j++)// if(a[i]>a[j]) 交换 2.先取出前k个排序,再取未排序的,若大于a[k-1],则忽略,否则插入适当位置并移去a[k

输入n个整数并找出其中的最小k个数

题目: 输入n个整数, 找出其中的最小k个数. 使用快速排序(Quick Sort)的方法求解, 把索引值(index)指向前k个数. 代码: /* * main.cpp * * Created on: 2014.6.12 * Author: Spike */ /*eclipse cdt, gcc 4.8.1*/ #include <stdio.h> #include <stdlib.h> int RandomInRange(int min, int max) { int rand

任意元素和-求一个数组中选出任意个数元素相加之和,求大神指教

问题描述 求一个数组中选出任意个数元素相加之和,求大神指教 求一个数组中选出任意个数元素相加之和,求大神指教 比如打印出arry[8]中,任意两个数相加的和,任意三个数相加的和,直到任意八个数相加的和. 求大神指教. 解决方案 不知道你用的什么语言 如果C#,参考我写的http://bbs.csdn.net/topics/390550326 这个问题其实就是求M选N,其中M=8,N循环1-8 然后得到每个组合再求和. 解决方案二: 不知道你使用的是什么语言,不过思路是这样的,你的要求是不是随机数

[华为机试练习题]45.求某二进制数中1的个数

题目 描述: 题目标题: 求某二进制数中1的个数. 给定一个unsigned int型的正整数,求其二进制表示中"1"的个数,要求算法的执行效率尽可能地高. 详细描述: 原型: int GetCount(unsigned int num) 输入参数: num 给定的正整数 输出参数(指针指向的内存区域保证有效): 无 返回值: 返回1的个数 举例: 输入13,则对应的二进制是1101,那么1的个数为3个.则:返回3. 练习阶段: 初级 代码 /*--------------------

python实现获取序列中最小的几个元素_python

本文实例讲述了python实现获取序列中最小的几个元素.分享给大家供大家参考. 具体方法如下: import heapq import random def issorted(data): data = list(data) heapq.heapify(data) while data: yield heapq.heappop(data) alist = [x for x in range(10)] random.shuffle(alist) print 'the origin list is'

【28】一个无序的序列查找第K大的数

题目:给定一个无序序列和一个数k,求这个无序序列中第K大的数 分析: 方案一:最朴素的方法利用快速排序然后找到第k个数,时间复杂度O(nlogn) 方案二:根据快速排序中的partition方法,每次可以把一个序列分成两个部分,左边全部小于等于基准,右边的全部大于等于基准.如果partition方法中基准的位置刚好是第k个则可以直接得多这个数,如果大于k说明在左边,如果小于k说明在右边.               利用这个方法每次可以将序列不断的划分直至找到这第k个数, 因为partition

寻找最小的k个数

题目描述 输入n个整数,输出其中最小的k个. 分析与解法 解法一 要求一个序列中最小的k个数,按照惯有的思维方式,则是先对这个序列从小到大排序,然后输出前面的最小的k个数. 至于选取什么的排序方法,我想你可能会第一时间想到快速排序(我们知道,快速排序平均所费时间为  n*logn  ),然后再遍历序列中前k个元素输出即可.因此,总的时间复杂度:  O(n * log n)+O(k)=O(n * log n)  . 解法二 咱们再进一步想想,题目没有要求最小的k个数有序,也没要求最后n-k个数有序

c++容器-关于 multiset 容器用法的疑问?问题来源于“找最小的k个数”

问题描述 关于 multiset 容器用法的疑问?问题来源于"找最小的k个数" 以下为"找最小k个数"中的一段代码,它使用了 multiset 容器,基于红黑树实现, 而这段算法的思想是 最大堆的思想,下面算法中 leastNumbers.begin() 应是指向最大值,这是为什么? 红黑树应是一颗二叉搜索树,为什么能保证 leastNumbers.begin() 指向最大值? typedef multiset<int, greater<int>