面试题(6)最小的K个数

题目:输入N个整数,找出其中最小的K个数,比如输入4,5,1,6,2,7,3,8这八个数,则最小的四个数字是:1,2,3,4

解法一:O(n)的算法:只有当我们可以修改输入的数组的时候可用

我们可以基于快速排序划分的方法来解决这个问题:如果基于数组的第k个数字来调整,使得比第k个数字小的元素都为与数组的左边,比第k个元素大的元素都位于数组的右边,这样调整后位于数组中左边的k个数,就是最小的k个数

参考代码如下:

#include<iostream>
#include<algorithm>
using namespace std;
int partition(int data[],int len,int start,int end)
{
    if(data == NULL || len <=0 || start < 0 || end >=start)
        return -1;
    int index = start;
    swap(data[index],data[end]);
    int small = start - 1;
    for(index = start;index < end;index++)
    {
        if(data[index] < data[end])
        {
            ++small;
            if(small != index)
                swap(data[index],data[small]);
        }
    }
    ++small;
    swap(data[small],data[end]);
    return small;
}
//最小的k个元素
void getLastKNumbers(int *input,int n,int *output,int k)
{
    if(input == NULL || output == NULL || n <= 0 || k > n || k<=0)
        return;
    int start = 0;
    int end = n - 1;
    int index = partition(input,n,start,end);
    while(index != k-1)
    {
        if(index > k-1)
        {
            end = index - 1;
            index = partition(input,n,start,end);
        }
        else
        {
            start = index - 1;
            index = partition(input,n,start,end);
        }
    }
    int i;
    for(i=0;i<k;i++)
    {
        output[i] = input[i];
    }
}

int main()
{
    int data[] = {4,5,1,6,2,7,3,8};
    int *output;
    getLastKNumbers(data,8,output,4);
    int i;
    for(i=0;i<4;i++)
        cout<<output[i]<<" ";
    cout<<endl;
    return 0;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

/*#define MAX(a,b) a>b?a:b
#define MIN(a,b) a>b?b:a
using namespace std;
const int N = 110;
int a[N];
bool cmp(int a,int b)
{
    return a<b;
}
int sumOffirstI(int n)
{
    int i,sum = 0;
    for(i=0;i<=n;i++)
        sum += a[i];
    return sum;
}
int main()
{
    int i,t,n;
    cin>>t;
    while(t--)
    {
        cin>>n;
        for(i=0;i<n;i++)
            cin>>a[i];
        sort(a,a+n,cmp);
        int sum = a[0];
        for(i=1;i<n;i++)
        {
            sum += sumOffirstI(i);
        }
        cout<<sum<<endl;
    }
    return 0;
}*/

 

 

 

 

 

 

 

 

 

 

 

/*int a[100010];
int max(int n)
{
    int Max,t,i;
    Max = a[0];
    t = a[0];
    for(i=1;i<n;i++)
    {
        if(t<0)
            t = a[i];
        else
            t+=a[i];
        Max = MAX(Max,t);
    }

    return Max;
}

int min(int n)
{
    int i,t,Min;
    t = a[0];
    Min = a[0];
    for(i=1;i<n;i++)
    {
        if(t>0)
            t = a[i];
        else
            t += a[i];
        Min = MIN(Min,t);
    }
    return Min;
}

int main()
{
    int n;
    while(cin>>n)
    {
        int sum = 0,i;
        for(i=0;i<n;i++)
        {
            cin>>a[i];
            sum += a[i];
        }
        cout<<(MAX(max(n),sum-min(n)))<<endl;
    }
    return 0;
}
*/

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

/*#include <iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 1010;
struct Node
{
    double left;//×î×ó±ß
    double right;//×îÓÒ±ß
}nodes[N];
bool cmp(Node a,Node b)
{
    return a.left < b.left;
}
int main()
{
    int n,d;
    while(cin>>n>>d)
    {
        if(n==0 && d==0)
            break;
        int i,x,y;
        bool flag = true;
        for(i=0;i<n;i++)
        {
            cin>>x>>y;
            if(y>d)
            {
                flag = false;
                continue;
            }
            double temp = sqrt(d*d - x*x);
            nodes[i].left = x - temp;
            nodes[i].right = x + temp;
        }
        sort(nodes,nodes+n,cmp);
        if(flag)
        {
            int count = 1;
            int Case=1;
            double r = nodes[0].right;
            for(i=1;i<n;i++)
            {
                if(nodes[i].left > r)
                {
                    count++;
                    r = nodes[i].right;
                }
                else
                {
                    if(nodes[i].right < r)
                        r = nodes[i].right;
                }
            }
            cout<<"Case "<<Case++<<": "<<count<<endl;
        }
        else
        {
            cout<<"-1"<<endl;
        }
    }
    return 0;
}*/
方法二:特别适合处理海量数据

我们可以先创建一个大小为k的集合来存储最小的k个元素,接下来我们每次从输入的n个数中读取一个数,如果集合中已有的数字的个数小于k,则直接把这个数放入到集合中,如果集合中已经有k个数,则找出集合中数的最大值,拿这个数和最大值进行比较,如果小于最大值的话,让其和最大值交换,或者舍弃,另外我们可以使用二叉树来存储集合

#include<iostream>
#include<set>
using namespace std;
typedef multiset<int,greater<int> >intSet;
typedef multiset<int greater<int> >::iterator setIterator;
void getKNUmbers(const vector<int>& data,intSet& leastNumbers,int k)
{
    leastNumbers.clear();
    if(k < 1 || data.size() <= k)
        return;
    vector<int>::iterator it = data.begin();
    for(;it != data.end();it++)
    {
        if(leastNumbers.size() < k)
            leastNumbers.insert(*it);
        else
        {
            setIterator its = leastNumbers.begin();
            if(*it < *(leastNumbers.begin()))
            {
                leastNumbers.erase(its);
                leastNumbers.insert(*it);
            }
        }
    }
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值