【29】求无序序列中最小k个数
2014-06-12 18:58
183 查看
题目:给定一个无序序列和一个数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
*/
分析:
方案一:最朴素的方法是利用快速排序,然后直接输出最小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
*/
相关文章推荐
- 每天学习一算法系列(29)(有两个序列a,b,大小都为n,序列元素的值任意整数,无序;要求:通过交换a,b 中的元素,使[序列a 元素的和]与[序列b 元素的和]之间的差最小)
- 有两个序列a,b,大小都为n,序列元素的值任意整数,无序; 要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小。
- 一个无序整数数组中找到最长连续序列(Longest Consecutive Sequence)和两个元素使得相差最小
- 写正确函数需要注意的地方:两个序列a,b,大小都为n,序列元素的值为任意整数,无序;要求通过交换a,b中的元素,使序列a元素的和与序列b元素的和之间的差最小
- 有两个序列a,b,大小都为 n,序列元素的值任意整数,无序 通过交换a,b中的元素,使序列 a的和与序列b的和之间的差最小
- [微软]有两个序列a,b,大小都为n,序列元素的值任意整数,无序; 要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小
- 有两个序列a,b,大小都为n,序列元素的值任意整数,无序;要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小。
- 有两个序列a,b,大小都为n,序列元素的值任意整数,无序;要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小。
- [微软]有两个序列a,b,大小都为n,序列元素的值任意整数,无序; 要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小
- 无序序列中O(n)时间复杂度寻找最小(最大)的K个数
- 《数组-规划》 有两个序列a,b,大小都为n,序列元素的值任意整数,无序;要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小
- java编程:两个无序数组a和b,交换a,b中的元素,使得[序列a元素的和]与[序列b元素的和]之间的差最小。
- 有两个序列a,b,大小都为n,序列元素的值任意整数,无序;要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小。
- 《数据结构与算法》学习笔记29 最小生成树
- 有两个序列a,b,大小都有n,序列元素的值任意整数,无序; 要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b无素的和]之间的差最大。
- 最小最序列和以及最小正子序列
- bzoj1006 弦图转完美消除序列,最小染色
- 【51Nod1476】括号序列的最小代价
- 序列a元素的和与序列b元素的和之间的差最小(32)
- 字符串_最小表示法求循环串的最小序列(HDU_4162)