面试题34:最小的K个数

题目:

输入n个整数,找出其中最小的K个数。

边界条件及异常:
n小于k,是否会有相同的数字

思路:

方法一:

先进行排序,然后输出最小的K个数

注意:会改变原来的数组

时间复杂度:O(nlgn)

空间复杂度:O(1)

方法二:

用额外的K个空间来存最小的K个数,再往后如果有小于这K个数的,按顺序插进来,并将较大的移出去。

用带排序的hash表(map和set带自动排序功能)来存储,插入操作时间复杂度O(lgK)

时间复杂度:O(nlgK)

空间复杂度:O(K)

#include <iostream>    
#include <vector> 
#include <queue>
#include <string>    
#include <stack>    
#include <algorithm>  
#include <hash_set>  //for hashtable
#include <hash_map>
#include <set>
using namespace std;

void getMinKNums(vector<int> nums, int k, set<int> &result)
{
	int size = nums.size();
	if (size < k) return;
	for (int i = 0; i < size; ++i)
	{
		if (i < k) result.insert(nums[i]);
		else
		{
			set<int>::iterator it = result.end();
			--it;
			if (nums[i] < *it)
			{
				result.erase(it);
				result.insert(nums[i]);
			}
		}
	}
}


int main()
{
	int arr[] = { 6, 7, 9, 8, 5, 4, 1, 2, 3 };
	vector<int> nums(arr, arr + 9);
	set<int> result;
	getMinKNums(nums, 4, result);
	
	set<int>::iterator it = result.begin();
	for (; it != result.end(); ++it)
		cout << *it << " ";
	cout << endl;
	return 0;
}

方法三:利用partition函数的思想,将原数组以第K个数为枢纽,小于该枢纽的值位于数组左边,大于该枢纽的值位于右边,最后再对前K个数进行排序即可。

时间复杂度:O(n)

#include <iostream>    
#include <vector> 
#include <queue>
#include <string>    
#include <stack>    
#include <algorithm>  
#include <hash_set>  //for hashtable
#include <hash_map>
#include <set>
#include <ctime>
using namespace std;

int RandomInRange(int start, int end)
{
	srand(time(0));
	return (rand() % (end-start) + start);
}

int Partition(vector<int> &data, int start, int end)
{
	int length = data.size();
	if (length <= 0 || start < 0 || end >= length) throw new std::exception("Invalid Parameters");
	int index = RandomInRange(start, end);
	swap(data[index], data[start]);    //将随机中枢交换的第一个
	int pivotkey = data[start];        //取第一个为中枢,且将中枢值存下来
	while (start < end)
	{
		while (start < end && data[end] >= pivotkey) --end;
		data[start] = data[end];
		while (start < end && data[start] <= pivotkey) ++start;
		data[end] = data[start];
	}
	data[start] = pivotkey;
	return start;
}

void getMinKNums(vector<int> nums, int k, vector<int> &result)
{
	int size = nums.size();
	if (size == 0 || size < k || k <= 0) return;
	int end = size - 1;
	int start = 0;
	int index = Partition(nums, start, end);
	while (index != k - 1)
	{
		if (index > k - 1)
		{
			end = index - 1;
			index = Partition(nums, start, end);
		}
		else
		{
			start = index + 1;
			index = Partition(nums, start, end);
		}
	}
	for (int i = 0; i < k; ++i)
		result.push_back(nums[i]);
}

int main()
{
	int arr[] = { 6, 7, 9, 8, 5, 4, 1, 2, 3 };
	vector<int> nums(arr, arr + 9);
	vector<int> result;
	getMinKNums(nums, 4, result);
	
	vector<int>::iterator it = result.begin();
	for (; it != result.end(); ++it)
		cout << *it << " ";
	cout << endl;
	return 0;
}


注意:方法二除了有不改变原来数据外,还有适合海量数据的输入。假设题目要求重海量数据中找出最小的K个数字,由于内存大小的限制,不可能把海量数据一次性全部载入内存。这时候可以借助辅助存储空间中每次读入一个数字。


你可能感兴趣的:(面试题34:最小的K个数)