题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4.
思路:
1、第一个思路肯定是通过排序,之后返回前k个数即可,时间复杂度O(nlogn);
2、利用Partition 的思想。找出划分位置index,index 前的数均比它小,index后的数均比它大。比较index与k-1的大小,决定下次划分的区间。当index==k-1时,那么0~index之间的数就是要求的数,时间复杂度O(n)
但这种方法需要修改输入的数组,若面试时要求可以修改,则可以用此方法
代码:牛客超时
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
int n=input.size();
int start=0;
int end=n-1;
vector<int>output;
if(k>n||k<0||n==0)
return output;
int index=Partition(input,start,end);
while(index!=k-1)
{
if(index>k-1)
{end=index-1;
index=Partition(input,start,end);}
else
{ start=index+1;
index=Partition(input,start,end);}
}
for(int i=0;i<k;i++)
output.push_back(input[i]);
return output;
}
int partition(vector<int>&A,int l,int r)
{
int i=l,x=nums[l];
int j=r;
while(i<j)
{
while(i<j&&nums[j]<x)
j--;
if(i<j)
nums[i++]=nums[j];
while(i<j&&nums[i]>=x)
i++;
if(i<j)
nums[j--]=nums[i];
}
nums[i]=x;
return i;
}
};
要求输出的k个最小数是经过排序的:
#include<bits/stdc++.h>
using namespace std;
int partition(vector<int>&s,int left,int right);
int main()
{
vector<int>input;
int n;
while(cin>>n)
input.push_back(n);
int length=input.size();
int start=0;
int end=length-2;
int k=input[length-1];
int index=partition(input,start,end);
while(index!=k-1)
{
if(index>k-1)
{end=index-1;
index=partition(input,start,end);}
else
{ start=index+1;
index=partition(input,start,end);}
}
sort(input.begin(),input.begin()+k);
for (int i = 0; i<k; i++)
{
if (i<k - 1)
cout << input[i] << " "; //前k个数格式:数字+空格
else
cout << input[i] << endl; //第K个数格式:数字+换行
}
return 0;
}
int partition(vector<int>&s,int left,int right)
{
int i=left,x=s[left];
int j=right;
while(i<j)
{
while(i<j&&s[j]>=x)
j--;
if(i<j)
s[i++]=s[j];
while(i<j&&s[i]<x)
i++;
if(i<j)
s[j--]=s[i];
}
s[i]=x;
return i;
}
3、使用基于二叉树的容器,创建一个大小为K的数据容器来存储最小的k个数字
- 可以先创建一个大小为k的数据容器来存储最小的k个数字,从输入的n个整数中一个一个读入放入该容器中,如果容器中的数字少于k个,按题目要求直接返回空;
- 如果容器中已有k个数字,而数组中还有值未加入,此时就不能直接插入了,而需要替换容器中的值。按以下步骤进行插入:
- 先找到容器中的最大值;
- 将待查入值和最大值比较,如果待查入值大于容器中的最大值,则直接舍弃这个待查入值即可;如果待查入值小于容器中的最小值,则用这个待查入值替换掉容器中的最大值;
- 重复上述步骤,容器中最后就是整个数组的最小k个数字。
使用set或multiset
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int>input, int k) {
int len=input.size();
if(len<=0||k>len) return vector<int>();
//仿函数中的greater<T>模板,从大到小排序
multiset<int, greater<int> > leastNums;
vector<int>::iterator vec_it=input.begin();
for(;vec_it!=input.end();vec_it++)
{
//将前k个元素插入集合
if(leastNums.size()<k)
leastNums.insert(*vec_it);
else
{
//第一个元素是最大值
multiset<int, greater<int> >::iterator greatest_it=leastNums.begin();
//如果后续元素<第一个元素,删除第一个,加入当前元素
if(*vec_it<*(leastNums.begin()))
{
leastNums.erase(greatest_it);
leastNums.insert(*vec_it);
}
}
}
return vector<int>(leastNums.begin(),leastNums.end());
}
};
此处用less<int>,greatest_it=leastNums.end()
为什么会出错????
优缺点比较:
总结:
当需要在某个数据容器内频繁查找以及替换最大值时,要想到二叉树是很好的选择,并能想到用堆或者红黑树等特殊的二叉树来实现。