// 面试题40:最小的k个数
// 题目:输入n个整数,找出其中最小的k个数。例如输入4、5、1、6、2、7、3、8
// 这8个数字,则最小的4个数字是1、2、3、4。
#include <set>
#include <vector>
#include <iostream>
#include <functional>
using namespace std;
// ====================方法1====================
//使用Partition函数,利用快排思想找到前K个数
/*Random Partition*/
int RandomInRange(int min, int max)
{
int random = rand() % (max - min + 1) + min;
return random;
}
void Swap(int* num1, int* num2)
{
int temp = *num1;
*num1 = *num2;
*num2 = temp;
}
int Partition(int data[], int length, int start, int end)//快排
{
if (data == nullptr || length <= 0 || start < 0 || end >= length)
throw new exception("Invalid Parameters");
int index = RandomInRange(start, end);//生成随机点
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;
}
/*核心算法*/
void GetLeastNumbers_Solution1(int* input, int n, int* output, int k)
{
if (input == nullptr || output == nullptr || 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====================
typedef multiset<int, greater<int> > intSet;//greater函数和less相反,这个谓词
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();//vector迭代器
for (; iter != data.end(); ++iter)
{
if ((leastNumbers.size()) < k)
leastNumbers.insert(*iter);
else
{
setIterator iterGreatest = leastNumbers.begin();//multiset迭代器
if (*iter < *(leastNumbers.begin()))
{
leastNumbers.erase(iterGreatest);//删除该条目
leastNumbers.insert(*iter);//插入新的,自动排序
}
}
}
}
// ====================测试代码====================
void Test(const char* testName, int* data, int n, int* expectedResult, int k)
{
if (testName != nullptr)
printf("%s begins: \n", testName);
vector<int> vectorData;
for (int i = 0; i < n; ++i)
vectorData.push_back(data[i]);
if (expectedResult == nullptr)
printf("The input is invalid, we don't expect any result.\n");
else
{
printf("Expected result: \n");
for (int i = 0; i < k; ++i)
printf("%d\t", expectedResult[i]);
printf("\n");
}
printf("Result for solution1:\n");
int* output = new int[k];
GetLeastNumbers_Solution1(data, n, output, k);
if (expectedResult != nullptr)
{
for (int i = 0; i < k; ++i)
printf("%d\t", output[i]);
printf("\n");
}
delete[] output;
printf("Result for solution2:\n");
intSet leastNumbers;
GetLeastNumbers_Solution2(vectorData, leastNumbers, k);
printf("The actual output numbers are:\n");
for (setIterator iter = leastNumbers.begin(); iter != leastNumbers.end(); ++iter)
printf("%d\t", *iter);
printf("\n\n");
}
// k小于数组的长度
void Test1()
{
int data[] = { 4, 5, 1, 6, 2, 7, 3, 8 };
int expected[] = { 1, 2, 3, 4 };
Test("Test1", data, sizeof(data) / sizeof(int), expected, sizeof(expected) / sizeof(int));
}
// k等于数组的长度
void Test2()
{
int data[] = { 4, 5, 1, 6, 2, 7, 3, 8 };
int expected[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
Test("Test2", data, sizeof(data) / sizeof(int), expected, sizeof(expected) / sizeof(int));
}
// k大于数组的长度
void Test3()
{
int data[] = { 4, 5, 1, 6, 2, 7, 3, 8 };
int* expected = nullptr;
Test("Test3", data, sizeof(data) / sizeof(int), expected, 10);
}
// k等于1
void Test4()
{
int data[] = { 4, 5, 1, 6, 2, 7, 3, 8 };
int expected[] = { 1 };
Test("Test4", data, sizeof(data) / sizeof(int), expected, sizeof(expected) / sizeof(int));
}
// k等于0
void Test5()
{
int data[] = { 4, 5, 1, 6, 2, 7, 3, 8 };
int* expected = nullptr;
Test("Test5", data, sizeof(data) / sizeof(int), expected, 0);
}
// 数组中有相同的数字
void Test6()
{
int data[] = { 4, 5, 1, 6, 2, 7, 2, 8 };
int expected[] = { 1, 2 };
Test("Test6", data, sizeof(data) / sizeof(int), expected, sizeof(expected) / sizeof(int));
}
// 输入空指针
void Test7()
{
int* expected = nullptr;
Test("Test7", nullptr, 0, expected, 0);
}
int main(int argc, char* argv[])
{
Test1();
Test2();
Test3();
Test4();
Test5();
Test6();
Test7();
system("pause");
return 0;
}