方法一:对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. NDEF-NFC数据交换格式

    为实现NFC标签.NFC设备以及NFC设备之间的交互通信,NFC论坛(NFC FROUM)定义了称为NFC数据交换格式(NDEF)的通用数据格式.NDEF是轻量级的紧凑的二进制格式,可带有URL,vC ...

  2. QReadWriteLock读写锁的一点测试(它是逻辑锁,并没有与实物相联系),只有锁住了读,才允许再次读,否则一概不允许

    QReadWriteLock m_lock; void MyWidget::Button1(){ m_lock.lockForRead(); ShowMessage(tr("111" ...

  3. 怎么让一个非窗口组件可以接受来自Windows的消息

    为什么要这样做? 有时候我们需要一个非窗口组件(比如一个非继承自TWinContrl的组件)可以接受Windows消息.要接受消息就需要一个窗口句柄,但是非窗口组件却没有句柄.这篇文章将讲述怎么让一个 ...

  4. eclipse启动tomcat 访问http://localhost:8080 报404错误

    eclipse启动tomcat 访问http://localhost:8080 报404错误 Server Locations修改后会变灰,如果需要更改设置,则需要移除与Tomcat服务器关联的项目, ...

  5. 纯CSS美化的checkbox 和 radio

    html <!DOCTYPE HTML> <html> <head> <title>纯CSS3实现自定义美化复选框和单选框</title> ...

  6. C语言的本质(14)——不完全类型和复杂声明

    ISO 将 C 的类型分为三个不同的集合: 函数.对象和不完全类型三大类.函数类型很明显:对象类型包含其他一切,除非不知道对象的大小.该标准使用术语"对象类型"指定指派的对象必须具 ...

  7. 10年程序员谈.Net程序员的职业规划(图/文)

    原文地址:http://bbs.csdn.net/topics/390736769 从事Dotnet程序开发工作近10年了,从开始的月薪3k的小程序员菜鸟,到现在年薪60w的项目总经理,从战战兢兢的去 ...

  8. IIS给网站地址配置成HTTPS的

    2.增加网站绑定 3.如果https的URL访问不了,可能是443端口被占用 然后netstat -anono

  9. 关系型数据库事务处理ACID

    ACID,指数据库事务正确执行的四个基本要素的缩写.包含:原子性(Atomicity).一致性(Consistency).隔离性 (Isolation).持久性(Durability).一个支持事务( ...

  10. 全国计算机等级考试二级教程-C语言程序设计_第4章_选择结构

    switch什么时候用break,什么时候不用break 调用break:一次执行一个分支,输入一个数据,对应一个级别 不调用break:连续执行多个分支 if...else 可以处理任何情况,大于小 ...