方法一:对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. Qt :非window子窗体的透明度设置

    ✿问题的由来            心血来潮,想利用QTimer 配合 setWindowOpacity()方法来实现一个窗体淡入的效果.   ✿实验代码    粗糙的实验代码: void Widge ...

  2. 【MYSQL 清空所有的的表中的数据的SQL的生成】

    MYSQL 清空所有的的表中的数据的SQL的生成 select Concat('TRUNCATE TABLE ', TABLE_NAME, ';') from INFORMATION_SCHEMA.T ...

  3. 注册flash.ocx inno setup (转)

    ; 脚本由 Inno Setup 脚本向导 生成! ; 有关创建 Inno Setup 脚本文件的详细资料请查阅帮助文档! #define MyAppName "xx模块" #de ...

  4. STM32F103控制两个步进电机按照一定转速比运动

    这个暑假没有回家,在学校准备九月份的电子设计竞赛.今天想给大家分享一下STM32定时器控制两个步进电机按照一定速度比转动的问题. 这次做的05年的电子设计竞赛题目,运动悬挂系统..本实验是控制两个步进 ...

  5. Map map=new HashMap(); 为什么是这样

    Map是接口,hashMap是Map的一种实现.接口不能被实例化. Map map=new HashMap(); 就是将map实例化成一个hashMap.这样做的好处是调用者不需要知道map具体的实现 ...

  6. COCI 2015/2016 Day 8 PROKLETNIK

    PROKLETNIK 题目描述:给出\(n\)个数,定义一段连续的数为魔法串是该区间的左右端点值正好是区间的最小值与最大值(最小值可以在左也可以在右,最大值也一样).\(Q\)个询问,每次询问一个区间 ...

  7. EasyUI Combotree 只允许选择 叶子节点

    $("#SDID").combotree({ url: '/Ajax/GetDeptTree.aspx?level=4&pid=-1', onSelect: functio ...

  8. #include <boost/shared_array.hpp>

    共享数组 共享数组的行为类型于共享指针.关键不同在于共享数组在析构时,默认使用delete[]操作符来释放所含的对象.因为这个操作符只能用于数组对象,共享数组必须通过动态分配的数组的地址来初始化.共享 ...

  9. IE下支持文本框和密码框placeholder效果的JQuery插件

    基于jQuery实现的,主要用于IE下实现placeholder效果,可同时支持文本和密码输入框.placeholder是HTML5新增的一个属性,当input设置了该属性后,该值的内容将作为灰色提示 ...

  10. HTML5实战与剖析之classList属性

    classList属性究竟是干什么的,我们先撇下classList不管.我们考虑这么一个问题,那就是我们如何将拥有多个类名的元素中的其中一个类名删除呢?梦龙较劲脑汁儿终于想到一个实现的方法.将拥有类名 ...