您的位置:首页 > Web前端

剑指offer:最小的k个数

2014-04-17 14:53 232 查看
题目:输入n个整数,找出其中最小的k个数。

方法1:上面一篇博客我们利用快速排序的partition函数来将数组分成两部分,partition函数的返回值就是排序好的数组的最终下标,其左边是比它小的数,右边是比它大的数,这样我们只需要将partition的返回值与k做比较,如果与k相等,则返回;如果比k大,则最小的k个数在左边,则继续返回递归;如果比k小,则最小的k个数中有一部分在右边,则返回这部分到右边寻找。

优点:时间复杂度为O(n),效率还是挺不错的。

缺点:我们找到的最小的K个数已经打乱了顺序了,就是不是原来输入的顺序,显然这不是一种好的方法,还有有缺陷的。

 void GetLeastNumbers_Solution1(int* input, int n, int* output, int k)
{
if(input == NULL || output == NULL || k > n || n <= 0 || 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);
}
}

for(int i = 0; i < k; ++i)
output[i] = input[i];
}
方法2:我们可以先创建一个大小为K的数据容器来存储最小的K个数,接下来我们每次从输入的n个整数中读入一个数,如果容器中已有的数字少于K,则直接把这次读入的整数放入容器中;如果容器中已有K个数,就是容器满了,此时我们不能插入新的数字而只能替换已有的数字了。找出这K个数的最大值,然后拿这次待插入的整数和最大值相比较。如果待插入的值比当前已有的最大值小,则用这个数替换当前已有的最大值;如果待插入的值比当前已有的最大值还大,那么这个数不可能是最小的K个整数之一,于是我们可以抛弃这个数。

我们可以用红黑树来实现这个数据容器,或者使用最大堆来实现。

第2种情况非常适合海量数据的处理,当n>>k的时候非常适合。

时间复杂度为:O(n*lgk)

typedef multiset<int, greater<int> >            intSet;
typedef multiset<int, greater<int> >::iterator  setIterator;

void GetLeastNumbers_Solution2(const vector<int>& data, intSet& leastNumbers, int k)
{
leastNumbers.clear();

if(k < 1 || data.size() < k)
return;

vector<int>::const_iterator iter = data.begin();
for(; iter != data.end(); ++ iter)
{
if((leastNumbers.size()) < k)
leastNumbers.insert(*iter);

else
{
setIterator iterGreatest = leastNumbers.begin();

if(*iter < *(leastNumbers.begin()))
{
leastNumbers.erase(iterGreatest);
leastNumbers.insert(*iter);
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: