数组篇

2.1 求最小的k个数:

题目描述:有n个整数,请找出其中最小的k个数,要求时间复杂度尽可能低。


解法一:

思路:快排后输出前k个元素,O(nlogn).

writer: zzq

function: 给定一个数组,寻找数组中最小的k个数。

方法一: 先对数组进行排序(快排), 然后选择前k个数。

快排思想: 分治挖坑

挖坑:

1) 先找到一个基准值a[i],存到key里面,然后把a[i]挖空;

2) 从j开始往前找(j--),找到第一个比key小的数,就用当前的a[j]来填补之前的a[i],把a[j]挖空;

3) 从i开始往后找(i++),找到第一个比key大的数,就用当前的a[i]来填补上面的a[i],再把a[i]挖空;

4) 如此循环,直到i==j;

5)然后把key中的值存到a[i]中。【此时,key前面的数都比key小,key后面的数都比key大】e.g.--------------,key,-----------------

分治:

以基准值key所在的位置作为划分点,

quicksort(*a,left,i-1) ;

quicksort(*a,i+1,right);

时间复杂度:排序O(nlogn) + 输出前k个元素O(k), k远小于n时,复杂度为O(nlogn)



#include<iostream>
#include<algorithm>
#include<string>
#include<stdio.h>
using namespace std; void QuickSort(int *a, int start, int end){
if(start<end){
//***************挖坑********************//
int i = start;
int j = end;
int key = *(a+start); // 用key来存中间阈值
// cout<<key<<endl;
while(i<j){ while(i<j&&*(a+j)>key)j--;// 从后往前找比key小的第一个元素
if(i<j){
*(a+i)=*(a+j);
i++;// 为什么只给i++,j的值不变呢,因为要记录当前的挖坑位置,下一次借助这个索引值来填坑。
}
while(i<j&&*(a+i)<key)i++;
if(i<j){
*(a+j)=*(a+i);
j--;
}
}
*(a+i)=key; // 将key填充到最终的坑中,此时满足key前面的元素逗比key小,key后面的元素都比key大。
//******************分治*****************//
QuickSort(a, start, i-1); // 左半部分
QuickSort(a, i+1 , end); // 右半部分
} } int main(){
int n,k;
cin>>n>>k;
int a[n];
for (int i=0;i<n;i++)cin>>a[i];
//int a[]= {72,6,57,88,60,42,83,73,48,85};
QuickSort(a,0,n-1);
for(int j=0;j<k;j++)cout<<a[j]<<' ';
return 0;
}

解法二:

思路:局部排序后输出k个元素,O(nk).

writer: zzq

function: 给定一个数组,寻找数组中最小的k个数。

方法二: 题目没有要求找到的k个最小数必须有序,也没有要求后面的n-k个数有序。

所以不必对整个数组进行排序,只需要对k个数部分排序即可。

1)顺序遍历数组a的前k个元素,保存在数组minK中;

2)选择排序|快速排序找出最大值kmax;

3)顺序遍历后面的n-k个数,如果比kmax大,则index++;否则用当前a[index]代替kmax,并重新对数组minK排序;

4)那么minK中保存的即为最小的k个数。

时间复杂度:(n-k)O(k)+O(k), k远小于n时, O(nk)

【 找minK中的最大值需要遍历k个元素:O(k);

每次更新or not;O(k)|0,共有n-k个待遍历元素, 所以为(n-k)O(k);

输出minK中的k个数:O(k)。


#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std; void GetMaxK(int *a,int length, int* KM){
int maxK=*a;
int index = 0;
for(int i=1;i<length;i++){
if(maxK<*(a+i)){
maxK=*(a+i);
index=i;
}
}
*KM=maxK;
*(KM+1)=index;
} int main(){
int n,k;
int KM[2];
cin>>n>>k;
int a[n],minK[k];
for(int i=0;i<n;i++){
cin>>a[i];
if(i<k)minK[i]=a[i];
}
GetMaxK(minK,k,KM);
for(int i=k;i<n;i++){
if(*KM>a[i]){ // a[i]比maxK小,替换该元素,重新求maxK
minK[*(KM+1)]=a[i];
GetMaxK(minK,k,KM);
}
}
for(int j=0;j<k;j++){
if(j+1==k)
cout<<minK[j]<<endl;
else
cout<<minK[j]<<' ';
}
return 0;
}

解法三:

思路:构建前k个数的大顶堆,每次跟新推后输出k个元素,O(nlogk).

writer: zzq

function: 给定一个数组,寻找数组中最小的k个数。

方法三: 利用堆代替数组。

1)用容量为k的最大堆minHk存储最先遍历到的k个数。建堆时间O(k),建好堆后,堆中元素有序,设minH1<minH2<···<minHk;

2)遍历剩余的n-k个元素,与堆顶元素hk比较,如果当前a[index]>minHk,则不做操作,否则用a[index]替换minHk,然后更新堆,

更新堆的时间为O(logk)

3)输出堆中元素即为所求。

时间复杂度:(n-k)O(logk)+O(k), k远小于n时, O(nlogk)

【 建堆:O(k);

更新堆:O(logk);[类似方法二,这是用堆代替数组以后,每次更新堆时间复杂度降低,因为堆是局部有序的]

每次更新or not;O(logk)|0,共有n-k个待遍历元素, 所以为(n-k)O(logk);

输出minK中的k个数:O(k)。】


   堆: 特殊的二叉树。
堆是具有以下性质的完全二叉树:
每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;
或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。
用数组实现,则结构描述为:
小顶堆:a[i]<=a[2*i+1]&&a[i]<=a[2*i+2];
大顶堆:a[i]>=a[2*i+1]&&a[i]>=a[2*i+2];


#include<iostream>
#include<algorithm>
using namespace std;
const int MaxN = 100010;
int B[MaxN]; void HeapRefresh(int *a, int index,int length){
int i = index;
int child = 2*i+1; // 使当前子树满足最小堆
while(child<length){ if(child<(length-1)&&*(a+child+1)>*(a+child)) // 右子节点存在,选择较小的子节点
child++;
if(*(a+child)>*(a+i)){
swap(*(a+child), *(a+i));
}
else{
break;
}
i = child;
child = 2*i+1;
}
} void CreatHeap(int *a, int length){
int j;
// length/2-1 为最后一个非叶节点
for(j = length/2-1;j>=0;j--){
HeapRefresh(a, j,length);
} }
int main(){
int n,k;
cin>>n>>k;
int minH[k];
for(int i=0;i<n;i++){
cin>>B[i];
if(i<k)minH[i]=B[i];
}
CreatHeap(minH,k);
for(int i=k;i<n;i++){
if(B[i]<minH[0]){
minH[0]=B[i];
HeapRefresh(minH,0,k);
}
}
for(int j=0;j<k;j++){
if(j+1==k)
cout<<minH[j]<<endl;
else
cout<<minH[j]<<' ';
}
return 0;
}

解法四:

思路:线性选择算法,O(n).

(未完待续)

编程之法section II: 2.1 求最小的k个数的更多相关文章

  1. 编程之法section II: 2.2 和为定值的两个数

    ====数组篇==== 2.2 求和为定值的两个数: 题目描述:有n个整数,找出其中满足两数相加为target的两个数(如果有多组满足,只需要找出其中一组),要求时间复杂度尽可能低. 解法一: 思路: ...

  2. php实现求最小的k个数(日常出错很容易是分号或者$符号忘记写了)

    php实现求最小的k个数(日常出错很容易是分号或者$符号忘记写了) 一.总结 日常出错很容易是分号或者$符号忘记写了 二.php实现求最小的k个数 题目描述 输入n个整数,找出其中最小的K个数.例如输 ...

  3. 求最小的k个数

    和高速排序有点类似,利用高速排序的划分算法, 划分算法见http://blog.csdn.net/buyingfei8888/article/details/8997803 依据int partiti ...

  4. 输入一个数组,求最小的K个数

    被这道题困了好久,看了剑指Offer才知道OJ上的要求有点迷惑性. 题目: 输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4. 一 ...

  5. 编程之法:面试和算法心得(寻找最小的k个数)

    内容全部来自编程之法:面试和算法心得一书,实现是自己写的使用的是java 题目描述 输入n个整数,输出其中最小的k个. 分析与解法 解法一 要求一个序列中最小的k个数,按照惯有的思维方式,则是先对这个 ...

  6. 编程之法:面试和算法心得(字符串包含java实现)

    内容全部来自编程之法:面试和算法心得一书,实现是自己写的使用的是java 题目描述 给定两个分别由字母组成的字符串A和字符串B,字符串B的长度比字符串A短.请问,如何最快地判断字符串B中所有字母是否都 ...

  7. 编程之法:面试和算法心得(旋转字符串java实现)

    内容全部来自编程之法:面试和算法心得一书,实现是自己写的使用的是java 题目描述 给定一个字符串,要求把字符串前面的若干个字符移动到字符串的尾部,如把字符串“abcdef”前面的2个字符'a'和'b ...

  8. 求一个数组中最小的K个数

    方法1:先对数组进行排序,然后遍历前K个数,此时时间复杂度为O(nlgn); 方法2:维护一个容量为K的最大堆(<算法导论>第6章),然后从第K+1个元素开始遍历,和堆中的最大元素比较,如 ...

  9. 求给定数据中最小的K个数

    public class MinHeap { /* * * Top K个问题,求给定数据中最小的K个数 * * 最小堆解决:堆顶元素为堆中最大元素 * * * */ private int MAX_D ...

随机推荐

  1. Ubuntu安装后配置

    配置源将所有源配置为华科(mirrors.hust.edu.cn)或者中科大源(mirrors.ustc.edu.cn)使用vi编辑,使用命令 :%s/ubuntu源地址.com/mirrors.hu ...

  2. 传统神经网络ANN训练算法总结

    传统神经网络ANN训练算法总结 学习/训练算法分类 神经网络类型的不同,对应了不同类型的训练/学习算法.因而根据神经网络的分类,总结起来,传统神经网络的学习算法也可以主要分为以下三类: 1)前馈型神经 ...

  3. 【HNOI2015】亚瑟王

    题面 题解 考虑进行\(dp\). 设\(f[i][j]\)表示前\(i\)张卡中有\(j\)张被触发的概率. 我们可以知道第\(i\)张卡不被触发的概率为\((1 - p_i) ^ {r - j}\ ...

  4. tcp三次握手四次挥手那些事

    建立TCP需要三次握手才能建立,而断开连接则需要四次挥手.三次握手,四次挥手流程图如下: 一.首先看下如何通过三次挥手----------建立连接 首先客户端发送连接请求报文,服务端接受连接后回复AC ...

  5. 日常的例子说明 throttle 和 debounce 的区别

    不小心接触到 throttle 和 debounce,按捺不住猎奇的心理,找这两个函数的资料. 然而百度到的各种对他们的理解,我去啊. 艰难地搞明白他们是干嘛的之后,忍不住举个例子说说自己的理解,希望 ...

  6. springmvc配置中,mapper一直依赖注入不进去的问题记录

    问题还原: service层在引用mapper层接口时,一直依赖注入不进去.查看spring-context.xml配置,也未发现异常[因为以前就是这么配置],但是始终无法注入. 原因: 问题不出在s ...

  7. nginx 配置 ssl 双向证书

    CA 根证书制作 # 创建 CA 私钥 openssl genrsa -out ca.key 2048 #制作 CA 根证书(公钥) openssl req -new -x509 -days 3650 ...

  8. RabbitMQ入门:路由(Routing)

    在上一篇博客<RabbitMQ入门:发布/订阅(Publish/Subscribe)>中,我们认识了fanout类型的exchange,它是一种通过广播方式发送消息的路由器,所有和exch ...

  9. css忽略某一层的存在:pointer-events:none

    其实早知道这个属性,但是一直没有去研究过.今天正好在twitter看到这个词,就去研究了下,正好解决了目前遇到的一个小难题,所以分享下.嗯,其实这是个比较简单的CSS3属性. 在某个项目中,很多元素需 ...

  10. OLAP和OLTP的区别

    OLAP(On-Line Analytical Processing)联机分析处理,也称为面向交易的处理过程,其基本特征是前台接收的用户数据可以立即传送到计算中心进行处理,并在很短的时间内给出处理结果 ...