方法一:对n个整数进行排序(快速排序或堆排序),取出前K个元素(最容易想到的最笨的方法,不可取)

时间复杂度:O(n*logn) + O(k) = O(n*logn)

采用快速排序的代码:

#include "stdafx.h"
#include <iostream>
using namespace std; //划分数组,找到枢轴元素下标,使得其左边的元素都比其小,右边的元素都比其大
int Partition(int nArr[], int nLength)
{
//初始状态下,选取数组的第一个元素作为枢轴元素
int nPivot = nArr[0]; //设置两个游标
int nLow = 0;
int nHigh = nLength - 1; while (nLow < nHigh)
{
while (nLow < nHigh && nArr[nHigh] >= nPivot)
{
nHigh--;
}
nArr[nLow] = nArr[nHigh]; while (nLow < nHigh && nArr[nLow] <= nPivot)
{
nLow++;
}
nArr[nHigh] = nArr[nLow];
} nArr[nLow] = nPivot;
return nLow;
} void FastSort(int nArr[], int nLength)
{
if (nArr == NULL || nLength <= 0)
{
return;
} int nMidIndex = Partition(nArr, nLength);
FastSort(nArr, nMidIndex);
FastSort(nArr + nMidIndex + 1, nLength - 1 - nMidIndex);
} int _tmain(int argc, _TCHAR* argv[])
{
int nArr1[8] = {4, 5, 1, 6, 2, 7, 3, 8};
int nArr2[8] = {4, 5, 2, 6, 2, 5, 3, 5};
int nArr3[8] = {1, 1, 1, 1, 1, 1, 1, 1}; while (1)
{
int k = 0;
cout << "请输入最小数的个数:";
cin >> k;
if (k == 0)
{
break;
} FastSort(nArr1, 8);
cout << "第一个数组的最小的" << k << "个数为:";
for (int i=0; i<k; i++)
{
cout << nArr1[i] << " ";
}
cout << endl; FastSort(nArr2, 8);
cout << "第二个数组的最小的" << k << "个数为:";
for (int i=0; i<k; i++)
{
cout << nArr2[i] << " ";
}
cout << endl; FastSort(nArr3, 8);
cout << "第三个数组的最小的" << k << "个数为:";
for (int i=0; i<k; i++)
{
cout << nArr3[i] << " ";
}
cout << endl;
} system("pause");
return 0;
}

运行结果:

采用堆排序的代码:

#include "stdafx.h"
#include <iostream>
using namespace std; //调整堆(大根堆)函数,待调整元素的下标nIndex,
void AdjustHeap(int nHeap[], int nLength, int nIndex)
{
int key = nHeap[nIndex];//待调整元素的值
for (int i=2*nIndex+1; i<nLength; i=2*i+1)
{
if (i+1 < nLength && (nHeap[i] < nHeap[i+1]))//有右孩子且右孩子的值比左孩子大
{
i++;//i指向表示较大孩子下标
}
if (nHeap[i] < key)//不需要调整
{
break;
}
nHeap[nIndex] = nHeap[i];
nIndex = i;
}
nHeap[nIndex] = key;
} //堆排序,从小到大
void HeapSort(int nArr[], int nLength)
{
if (nArr != NULL && nLength > 0)
{
for (int i=nLength/2-1; i>=0; i--)
{
AdjustHeap(nArr, nLength, i);//调整为大根堆
} for (int j=nLength-1; j>=0; j--)
{
int temp = nArr[j];
nArr[j] = nArr[0];
nArr[0] = temp;
AdjustHeap(nArr, j, 0);
}
}
else
{
return ;
}
} int _tmain(int argc, _TCHAR* argv[])
{
int nArr1[8] = {4, 5, 1, 6, 2, 7, 3, 8};
int nArr2[8] = {4, 5, 2, 6, 2, 5, 3, 5};
int nArr3[8] = {1, 1, 1, 1, 1, 1, 1, 1}; while (1)
{
int k = 0;
cout << "请输入最小数的个数:";
cin >> k;
if (k == 0)
{
break;
} HeapSort(nArr1, 8);
cout << "第一个数组的最小的" << k << "个数为:";
for (int i=0; i<k; i++)
{
cout << nArr1[i] << " ";
}
cout << endl; HeapSort(nArr2, 8);
cout << "第二个数组的最小的" << k << "个数为:";
for (int i=0; i<k; i++)
{
cout << nArr2[i] << " ";
}
cout << endl; HeapSort(nArr3, 8);
cout << "第三个数组的最小的" << k << "个数为:";
for (int i=0; i<k; i++)
{
cout << nArr3[i] << " ";
}
cout << endl;
} system("pause");
return 0;
}

运行结果:


方法二:使用选择排序或冒泡排序,进行K次选择,可得到最小的k个数

时间复杂度:O(n*k)

选择排序代码:

#include "stdafx.h"
#include <iostream>
using namespace std; //利用选择排序找到最小的k个数,进行k次选择即可
void SelectSort_KMinNum(int nArr[], int nLength, int k)
{
if (nArr == NULL || nLength <= 0 || k>nLength)
{
cout << "输入有误!" << endl;
return;
} int nMin = 0;
int nMinIndex = 0;
for (int i=0; i<k; i++)//进行k次选择
{
nMin = nArr[i];
nMinIndex = i;
for (int j=i+1; j<nLength; j++)
{
if (nArr[j] < nMin)
{
nMin = nArr[j];
nMinIndex = j;
}
} if (i != nMinIndex)
{
int temp = nArr[i];
nArr[i] = nArr[nMinIndex];
nArr[nMinIndex] = temp;
} cout << nArr[i] << " ";
}
cout << endl; } int _tmain(int argc, _TCHAR* argv[])
{
int nArr1[8] = {4, 5, 1, 6, 2, 7, 3, 8};
int nArr2[8] = {4, 5, 2, 6, 2, 5, 3, 5};
int nArr3[8] = {1, 1, 1, 1, 1, 1, 1, 1}; while (1)
{
int k = 0;
cout << "请输入最小数的个数:";
cin >> k;
if (k == 0)
{
break;
} cout << "第一个数组的最小的" << k << "个数为:";
SelectSort_KMinNum(nArr1, 8, k); cout << "第二个数组的最小的" << k << "个数为:";
SelectSort_KMinNum(nArr2, 8, k); cout << "第三个数组的最小的" << k << "个数为:";
SelectSort_KMinNum(nArr3, 8, k);
}
system("pause");
return 0;
}

运行结果:

冒泡排序代码:

#include "stdafx.h"
#include <iostream>
using namespace std; //利用冒泡排序找到最小的k个数,进行k次选择即可
void BubbleSort_KMinNum(int nArr[], int nLength, int k)
{
if (nArr == NULL || nLength <= 0 || k>nLength)
{
cout << "输入有误!" << endl;
return;
} for (int i=1; i<=k; i++)//进行k次冒泡过程
{
for (int j=0; j<nLength-i; j++)
{
if (nArr[j] < nArr[j+1])
{
int temp = nArr[j];
nArr[j] = nArr[j+1];
nArr[j+1] = temp;
}
} cout << nArr[nLength-i] << " ";
}
cout << endl;
} int _tmain(int argc, _TCHAR* argv[])
{
int nArr1[8] = {4, 5, 1, 6, 2, 7, 3, 8};
int nArr2[8] = {4, 5, 2, 6, 2, 5, 3, 5};
int nArr3[8] = {1, 1, 1, 1, 1, 1, 1, 1}; while (1)
{
int k = 0;
cout << "请输入最小数的个数:";
cin >> k;
if (k == 0)
{
break;
} cout << "第一个数组的最小的" << k << "个数为:";
BubbleSort_KMinNum(nArr1, 8, k); cout << "第二个数组的最小的" << k << "个数为:";
BubbleSort_KMinNum(nArr2, 8, k); cout << "第三个数组的最小的" << k << "个数为:";
BubbleSort_KMinNum(nArr3, 8, k);
}
system("pause");
return 0;
}

运行结果:

方法三
计数排序 + 数组实现 
适合数据量小的数据,不提倡使用

使用计数排序,另开辟一个数组,记录每个整数出现的次数,然后再从大到小取最大的 K 个。

代码:

#include "stdafx.h"
#include <iostream>
using namespace std; //利用计数+数组找到最小的k个数
void CountArr_KMinNum(int nArr[], int nLength, int k)
{
if (nArr == NULL || nLength <= 0 || k>nLength)
{
cout << "输入有误!" << endl;
return;
} int nMax = nArr[0];
for (int i=1; i<nLength; i++)
{
if (nMax < nArr[i])
{
nMax = nArr[i];
}
} int *pArr = new int[nMax+1];//开辟一个数组
memset(pArr, 0, (nMax+1)*sizeof(int)); for (int j=0; j<nLength; j++)
{
pArr[nArr[j]]++;
} int nCount = 0;
for (int z=0; z<nMax+1; z++)
{
if (pArr[z]>0)
{
while ((pArr[z]--)>0)
{
if (nCount < k)
{
cout << z << " ";
nCount++;
}
else
{
break;
}
}
}
} delete []pArr;
pArr = NULL;
cout << endl;
} int _tmain(int argc, _TCHAR* argv[])
{
int nArr1[8] = {4, 5, 1, 6, 2, 7, 3, 8};
int nArr2[8] = {4, 5, 2, 6, 2, 5, 3, 5};
int nArr3[8] = {1, 1, 1, 1, 1, 1, 1, 1}; while (1)
{
int k = 0;
cout << "请输入最小数的个数:";
cin >> k;
if (k == 0)
{
break;
} cout << "第一个数组的最小的" << k << "个数为:";
CountArr_KMinNum(nArr1, 8, k); cout << "第二个数组的最小的" << k << "个数为:";
CountArr_KMinNum(nArr2, 8, k); cout << "第三个数组的最小的" << k << "个数为:";
CountArr_KMinNum(nArr3, 8, k);
}
system("pause");
return 0;
}

运行结果:

方法四、利用STL中的map保存每个数出现的次数,找到K个数

时间复杂度O(n*logn)     空间复杂度O(n)

注意:1、不能使用CMap实现,因为Cmap不能根据key自动为其排序;2、map内部是由红黑树实现的,每次插入都是logn,总的复杂度为n*logn。

代码:

#include "stdafx.h"
#include <iostream>
#include <map>
using namespace std; //利用map计数找到最小的k个数
void MapCount_KMinNum(int nArr[], int nLength, int k)
{
if (nArr == NULL || nLength <= 0 || k>nLength)
{
cout << "输入有误!" << endl;
return;
} map<int,int> countMap; for (int j=0; j<nLength; j++)
{
if (countMap[nArr[j]]==0)
{
countMap[nArr[j]] = 1;
}
else
{
countMap[nArr[j]]++;
}
} int nCount = 0;
for (map<int, int>::iterator itr=countMap.begin(); itr!=countMap.end(); itr++)
{
if (itr->second > 0)
{
while ((itr->second--) > 0)
{
if (nCount < k)
{
cout << itr->first << " ";
nCount++;
}
else
{
break;
}
}
}
}
cout << endl;
} int _tmain(int argc, _TCHAR* argv[])
{
int nArr1[8] = {4, 5, 1, 6, 2, 7, 3, 8};
int nArr2[8] = {4, 5, 2, 6, 2, 5, 3, 5};
int nArr3[8] = {1, 1, 1, 1, 1, 1, 1, 1}; while (1)
{
int k = 0;
cout << "请输入最小数的个数:";
cin >> k;
if (k == 0)
{
break;
} cout << "第一个数组的最小的" << k << "个数为:";
MapCount_KMinNum(nArr1, 8, k); cout << "第二个数组的最小的" << k << "个数为:";
MapCount_KMinNum(nArr2, 8, k); cout << "第三个数组的最小的" << k << "个数为:";
MapCount_KMinNum(nArr3, 8, k);
}
system("pause");
return 0;
}

运行结果:

方法五、维护一个大小为k的大根堆,初始化为数组中前k个元素,调整为大根堆。对于数组中的剩下的数,判断与堆顶的大小。如果比堆顶大,则不需要改变原来的堆;如果比堆顶小,要将其替换堆顶的元素,调整为大根堆。

时间复杂度: O (N * log2 K ),算法只需扫描所有的数一次,调整堆的时间复杂度为O(log2K)

空间复杂度:O(k),需一个大小为k 的堆。

代码:

#include "stdafx.h"
#include <iostream>
using namespace std; //调整堆(大根堆)函数,待调整元素的下标nIndex,
void AdjustHeap(int nHeap[], int nLength, int nIndex)
{
int key = nHeap[nIndex];//待调整元素的值
for (int i=2*nIndex+1; i<nLength; i=2*i+1)
{
if (i+1 < nLength && (nHeap[i] < nHeap[i+1]))//有右孩子且右孩子的值比左孩子大
{
i++;//i指向表示较大孩子下标
}
if (nHeap[i] < key)//不需要调整
{
break;
}
nHeap[nIndex] = nHeap[i];
nIndex = i;
}
nHeap[nIndex] = key;
} //找到数组nArr中最小的k个数
int* MinKNum(int nArr[], int nLength, int k)
{
if (nArr != NULL && nLength > 0 && k <= nLength)
{
//维护一个大小为k的大根堆,初始化为数组的前k个元素
int *nHeap = new int[k];
for (int i=0; i<k; i++)
{
nHeap[i] = nArr[i];
}
for (int t=k/2-1; t>=0; t--)
{
AdjustHeap(nHeap, k, t);//调整为大根堆
} for (int j=k; j<nLength; j++)
{
if (nArr[j] < nHeap[0])//剩下的元素依次与堆顶元素进行比较,若比其小则替换堆顶元素
{
nHeap[0] = nArr[j];
AdjustHeap(nHeap, k, 0);
}
}
return nHeap;
}
else
{
return NULL;
}
} int _tmain(int argc, _TCHAR* argv[])
{
int nArr[8] = {4, 5, 1, 6, 2, 7, 3, 8};
//int nArr[8] = {1, 2, 3, 4, 5, 6, 7, 8};
//int nArr[8] = {2, 2, 2, 2, 2, 2, 2, 2};
int k = 0;
while (1)
{
cout << "请输入最小数的个数:";
cin >> k;
if (k == 0)//输入0表示程序结束
{
break;
}
int *p_nHeap = MinKNum(nArr, 8, k);
cout << "最小的" << k << "个数为:";
for (int i=0; i<k; i++)
{
cout << p_nHeap[i] << " ";
}
cout << endl; delete [] p_nHeap;
p_nHeap = NULL;
} system("pause");
return 0;
}

运行结果:

面试题25:最小的K个数的更多相关文章

  1. 剑指Offer:面试题30——最小的k个数(java实现)

    问题描述: 输入n个整数,找出其中最小的k个数 思路1: 先排序,再取前k个 时间复杂度O(nlogn) 下面给出快排序的代码(基于下面Partition函数的方法) public void Quic ...

  2. 面试题30.最小的k个数

    题目:输入n个整数,找出其中最小的k个数,例如输入4,5,1,6,2,7,3,8 这8个数字,则最小的四个数字为1,2,3,4, 这道题是典型的TopK问题,剑指Offer提供了两种方法来实现,一种方 ...

  3. 剑指offer 面试题40. 最小的k个数

    O(N)划分法,注意这个方法会改变原数据(函数参数是引用的情况下)!当然也可以再定义一个新容器对其划分 要求前k小的数,只要执行快排划分,每次划分都会把数据分成大小两拨.直到某一次划分的中心点正好在k ...

  4. leetcode 签到 面试题40. 最小的k个数

    题目 输入整数数组 arr ,找出其中最小的 k 个数.例如,输入4.5.1.6.2.7.3.8这8个数字,则最小的4个数字是1.2.3.4. 示例 1: 输入:arr = [3,2,1], k = ...

  5. 《剑指offer》面试题40. 最小的k个数

    问题描述 输入整数数组 arr ,找出其中最小的 k 个数.例如,输入4.5.1.6.2.7.3.8这8个数字,则最小的4个数字是1.2.3.4. 示例 1: 输入:arr = [3,2,1], k ...

  6. 【面试题030】最小的k个数

    [面试题030]最小的k个数 题目:     输入n个整数,找出其中最小的k个数.     例如输入4.5.1.6.2.7.3.8这8个字,则其中最小的4个数字是1.2.3.4.     思路一:   ...

  7. 【剑指Offer面试题】 九度OJ1371:最小的K个数

    题目链接地址: http://ac.jobdu.com/problem.php?pid=1371 题目1371:最小的K个数 时间限制:1 秒内存限制:32 兆特殊判题:否提交:5938解决:1265 ...

  8. 面试题40:最小的 k 个数

    import java.util.Arrays; /** * Created by clearbug on 2018/2/26. * * 面试题40:最小的 k 个数 * * 注意:因为前两天在陌陌面 ...

  9. 剑指Offer面试题:27.最小的k个数

    一.题目:最小的k个数 题目:输入n个整数,找出其中最小的k个数.例如输入4.5.1.6.2.7.3.8这8个数字,则最小的4个数字是1.2.3.4. 这道题是典型的TopK问题,其最简单的思路莫过于 ...

随机推荐

  1. android---EditText黄色边框

    http://liuzhichao.com/p/612.html 自定义android控件EditText边框背景 柳志超博客 » Program » Andriod » 自定义android控件Ed ...

  2. 解决C/C++程序执行一闪而过的方法(三种办法)

    简述 在VS编写控制台程序的时候,包括使用其他IDE(Visual C++)编写C/C++程序,经常会看到程序的执行结果一闪而过,要解决这个问题,可以在代码的最后加上system(“pause”).g ...

  3. google地图marker文字label添加js lib

    google的地图marker需要使用js开发库,文件并允许使用js库 在JSP页面中需要添加地图引用如: <script src="http://maps.googleapis.co ...

  4. 写一个产生16位纯数字唯一 ID 的方法,要求时间因素的介入。(不要求绝对唯一,在一定的时空中重复机率很小即可)

    function randomID () { _random = function(min, max) { if (max == null) { max = min; min = 0; } retur ...

  5. hdu 5506 GT and set(dfs爆搜)

    Problem Description You are given N sets.The i−th set has Ai numbers.You should divide the sets into ...

  6. c#中(int)、int.Parse()、int.TryParse、Convert.ToInt32的区别

    本文来自:http://blog.csdn.net/tangjunping/article/details/5443337 以前经常为这几种数据类型转换方式而迷茫,这次为了彻底搞清它们之间的区别和优缺 ...

  7. 连不上VSS 【转】

    今天打开项目,但是连不上VSS,报错如下: (一)现象: Could not find the Visual SourceSafe Internet Web Service connection in ...

  8. 如何确定Ubuntu下是否对某个CVE打了补丁

        前些日子在月赛中,拿到了一台Ubuntu14.04的服务器,但并不是root权限,需要提权.我Google了一下,找到了CVE-2015-1318,CVE-2015-1328,CVE-2015 ...

  9. 根据Model有值的自动生成添加的Sql语句

    static string Table_Name = ""; /// <summary> /// model实体中的字段名相对数据库表添加的字段 /// 如: /// ...

  10. 理解js异步的概念

    js引擎在执行的时候是单线程的,这是大家都知道的.我们先来看一段代码: <html> <head> <meta http-equiv="Content-Type ...