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

简介: 题目:给定一个无序序列和一个数k,求最小k个数(不要求数字有序)分析:方案一:最朴素的方法是利用快速排序,然后直接输出最小k个数,时间复杂度为O(nlogn)方案二:利用快速排序的partition函数的性质,根据基准的性质,每次可以把序列分成两个部分,左边序列全部小于等于基准的值,右边序列全部大于等于序列的值。


题目:给定一个无序序列和一个数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 
*/


目录
相关文章
|
4月前
|
算法 测试技术 C#
C++二分查找算法的应用:长度递增组的最大数目
C++二分查找算法的应用:长度递增组的最大数目
|
4月前
|
搜索推荐 算法 测试技术
C++归并排序算法的应用:计算右侧小于当前元素的个数
C++归并排序算法的应用:计算右侧小于当前元素的个数
|
2月前
|
算法 测试技术 C++
【动态规划】【C++算法】801. 使序列递增的最小交换次数
【动态规划】【C++算法】801. 使序列递增的最小交换次数
|
4月前
|
算法 测试技术 C++
C++二分查找算法:有序矩阵中的第 k 个最小数组和(一)
C++二分查找算法:有序矩阵中的第 k 个最小数组和
|
4月前
|
算法 测试技术 C#
C++二分查找算法:有序矩阵中的第 k 个最小数组和(二)
C++二分查找算法:有序矩阵中的第 k 个最小数组和
|
8月前
|
人工智能
有序序列中插入一个整数
有序序列中插入一个整数
50 0
|
9月前
|
Cloud Native Go
801. 使序列递增的最小交换次数:动态规划
这是 力扣上的 801. 使序列递增的最小交换次数,难度为 困难。
|
11月前
7-234 两个有序序列的中位数
7-234 两个有序序列的中位数
78 0
两个有序序列的中位数
两个有序序列的中位数
93 0
数组——209.长度最小的子数组
本专栏按照数组—链表—哈希—字符串—栈与队列—二叉树—回溯—贪心—动态规划—单调栈的顺序刷题,采用代码随想录所给的刷题顺序,一个正确的刷题顺序对算法学习是非常重要的,希望对大家有帮助