编程之法section II: 2.1 求最小的k个数
数组篇
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个数的更多相关文章
- 编程之法section II: 2.2 和为定值的两个数
====数组篇==== 2.2 求和为定值的两个数: 题目描述:有n个整数,找出其中满足两数相加为target的两个数(如果有多组满足,只需要找出其中一组),要求时间复杂度尽可能低. 解法一: 思路: ...
- php实现求最小的k个数(日常出错很容易是分号或者$符号忘记写了)
php实现求最小的k个数(日常出错很容易是分号或者$符号忘记写了) 一.总结 日常出错很容易是分号或者$符号忘记写了 二.php实现求最小的k个数 题目描述 输入n个整数,找出其中最小的K个数.例如输 ...
- 求最小的k个数
和高速排序有点类似,利用高速排序的划分算法, 划分算法见http://blog.csdn.net/buyingfei8888/article/details/8997803 依据int partiti ...
- 输入一个数组,求最小的K个数
被这道题困了好久,看了剑指Offer才知道OJ上的要求有点迷惑性. 题目: 输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4. 一 ...
- 编程之法:面试和算法心得(寻找最小的k个数)
内容全部来自编程之法:面试和算法心得一书,实现是自己写的使用的是java 题目描述 输入n个整数,输出其中最小的k个. 分析与解法 解法一 要求一个序列中最小的k个数,按照惯有的思维方式,则是先对这个 ...
- 编程之法:面试和算法心得(字符串包含java实现)
内容全部来自编程之法:面试和算法心得一书,实现是自己写的使用的是java 题目描述 给定两个分别由字母组成的字符串A和字符串B,字符串B的长度比字符串A短.请问,如何最快地判断字符串B中所有字母是否都 ...
- 编程之法:面试和算法心得(旋转字符串java实现)
内容全部来自编程之法:面试和算法心得一书,实现是自己写的使用的是java 题目描述 给定一个字符串,要求把字符串前面的若干个字符移动到字符串的尾部,如把字符串“abcdef”前面的2个字符'a'和'b ...
- 求一个数组中最小的K个数
方法1:先对数组进行排序,然后遍历前K个数,此时时间复杂度为O(nlgn); 方法2:维护一个容量为K的最大堆(<算法导论>第6章),然后从第K+1个元素开始遍历,和堆中的最大元素比较,如 ...
- 求给定数据中最小的K个数
public class MinHeap { /* * * Top K个问题,求给定数据中最小的K个数 * * 最小堆解决:堆顶元素为堆中最大元素 * * * */ private int MAX_D ...
随机推荐
- 对象关系映射(ORM)
1.什么是 对象-关系映射 对象-关系映射(Object Relational Mapping,简称ORM,对象关系映射)是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术. 简单的说,OR ...
- #leetcode刷题之路50-Pow(x, n)
实现 pow(x, n) ,即计算 x 的 n 次幂函数.示例 1:输入: 2.00000, 10输出: 1024.00000示例 2:输入: 2.10000, 3输出: 9.26100 #inclu ...
- CPP strcat函数使用
strcat函数原型 char * strcat ( char * destination, const char * source ); strcat常见写法 // main.cpp // 字符数组 ...
- Ubuntu安装ss
安装环境:ubuntu 16.04 (推荐使用此版本-2019年3月) 本文假设读者已经拥有一台vps. 安装ss 首先通过终端以root身份登录vps $ ssh root@[IP Address] ...
- SQLAlchemy Table(表)类方式 - Table类和Column类
Table 构造方法 Table(name, metadata[, *column_list][, **kwargs]) 参数说明: name 表名 metadata 元数据对象 column_lis ...
- IIC总线(集成电路总线)
三大串行总线:UART.SPI.IIC(其中SPI是由时钟沿采集数据,为同步接口:UART和IIC是由电平采集数据,为异步接口) IIC速率:工作在半双工方式,2根线(SCL和SDA) 标准:100k ...
- python基础学习1-列表推导式和字典推导式
#!/usr/bin/env python # -*- coding:utf-8 -*- #列表推导式 取得100内可以被2整除且不能被3整除的数字 a=[i for i in range(100) ...
- [Windows]_[中级]_[崩溃报告的中级解决方案]
场景 1.在Windows上用C/C++开发软件, 经常会出现软件级别的崩溃情况, 如果用户看到这种崩溃报告, 那么一般会认为软件质量不高, 从而不想用. Windows上就会有崩溃报告这种噢给你工具 ...
- 3530: [Sdoi2014]数数
3530: [Sdoi2014]数数 链接 分析: 对给定的串建立AC自动机,然后数位dp.数位dp的过程中,记录当前在AC自动机的哪个点上,保证不能走到出现了给定串的点. 代码: #include& ...
- cogs 421 [SDOI2009]HH的项链
主席树.比树状数组高端多了又好写. last[i]表示上一个颜色为i的数,没有则为0. 那么一个区间里的答案就显而易见了: \(\sum_{i=l}^r (last[i]<l)\) 上面的东西已 ...