题目:n个数中,求最小的前k个数。

这道题在各个地方都看到过,在国内出现的频率也非常高。

面完阿里回来听说这道题又被考了,所以还是决定回来写一写,对于这种高频题。。。顺便再吐槽一下阿里的面试,我竟然一道题都不用做,只是纯粹地过简历。。。导致我都不知道我究竟错在哪里。

解法:

1. brute force。 O(k*n)复杂度;

2. sort。O(k+n*lgn)复杂度;

3. 最大堆。每次替代的是大小为k的最大堆的最大值。O(k+(n-k)lgk)复杂度。

 int findKthByHeap(int arr[], int n, int k) {
make_heap(arr, arr + k); for (int i = k; i < n; ++i) {
if (arr[i] < arr[]) {
pop_heap(arr, arr + k); // pop_heap()用于弹出堆中的第一个元素,并把它放到区间的最后一个位置,然后重新将前面的元素构建成一个堆。
arr[k - ] = arr[i]; //替换最后一个数
push_heap(arr, arr + k); //pop_heap()用于将指定区间的最后一个元素加入堆中并使整个区间成为一个新的堆。注意前提是最后一个元素除外的所有元素已经构成一个堆。
}
} return arr[];
}

4. 最小堆。和sort类似,只是建堆后只求前k次。O(n+k*lgn)复杂度。在网上看到一个优化,就是pop出第k小的数(堆顶)的时候,最多只需要调整k-1层(不需要调到堆底)。所以可以优化到O(n+k^2)。当然这个建堆需要O(n)的空间复杂度,所以还是弱一点。

 int findKthByHeap(int arr[], int n, int k) {
make_heap(arr, arr + n, greater<int>());
for (int i = ; i < k - ; ++i) {
pop_heap(arr, arr + n, greater<int>());
n--;
}
return arr[];
}

5. 类quick sort。求第k小的数。pivot用的是“五分化中项的中项”。因为每次划分之后,只需要考虑其中一部分的数,证明过程类似于堆排序建堆用了O(n)的开销证明。开销也在O(n)。

关于partition,要用的是双向划分, 避免的是所有数字都相等的情况。

双向划分也有两种方式,最后一种最为简洁,关键在于arr[l]这个元素因为先保存下来了,所以替换它是安全的,所以我们是先找arr[r],然后将它保存到arr[l];然后再找arr[l],将它保存到arr[r]。循环退出时,arr[l]已经保存到arr[r]的位置了,所以循环不变式是arr[l]仍然可以安全地被替代。

 int partition2(int arr[], int n) {
int l = ;
for (int i = ; i < n; ++i) {
if (arr[i] < arr[]) {
swap(arr[++l], arr[i]);
}
}
swap(arr[], arr[l]);
return l;
} int partition(int arr[], int n) {
int l = , r = n;
while (true) {
while (++l < n && arr[l] < arr[]);
while (arr[--r] > arr[]);
if (l >= r) break;
swap(arr[l], arr[r]);
}
swap(arr[], arr[r]);
return r;
} int partition3(int arr[], int n) {
int l = , r = n - ;
int p = arr[];
while (l < r) {
while (r > l && arr[r] >= p) r--;
arr[l] = arr[r];
while (r > l && arr[l] <= p) l++;
arr[r] = arr[l];
}
arr[l] = p;
return l;
} int quickSelect(int arr[], int n, int k) {
int p = partition3(arr, n);
if (p == k - ) return arr[p];
else if (p < k - ) {
return quickSelect(arr + p + , n - p - , k - p - );
} else {
return quickSelect(arr, p, k);
}
}

“五分化中项的中项”划分法:

  • 将输入数组的N个元素划分为[n/5]组,最后一个组剩下的n mod5组成;
  • 寻找每一组的中位数:首先对每组的元素进行插入排序,排序后选出一些中位数;这样可以确保,对于这一些中位数,大于它们的数的个数约等于小于它们的数的个数;
  • 对找出的[n/5]个中位数,继续递归找到其中位数,作为最终的pivot;
  • 基于pivot进行partition划分;

找到n中最小的k个数的更多相关文章

  1. 找到数组中最小的k个数

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

  2. 【算法】数组与矩阵问题——找到无序数组中最小的k个数

    /** * 找到无序数组中最小的k个数 时间复杂度O(Nlogk) * 过程: * 1.一直维护一个有k个数的大根堆,这个堆代表目前选出来的k个最小的数 * 在堆里的k个元素中堆顶的元素是最小的k个数 ...

  3. [算法]找到无序数组中最小的K个数

    题目: 给定一个无序的整型数组arr,找到其中最小的k个数. 方法一: 将数组排序,排序后的数组的前k个数就是最小的k个数. 时间复杂度:O(nlogn) 方法二: 时间复杂度:O(nlogk) 维护 ...

  4. 《程序员代码面试指南》第八章 数组和矩阵问题 找到无序数组中最小的k 个数

    题目 找到无序数组中最小的k 个数 java代码 package com.lizhouwei.chapter8; /** * @Description: 找到无序数组中最小的k 个数 * @Autho ...

  5. 小米笔试题:无序数组中最小的k个数

    题目描述 链接:https://www.nowcoder.com/questionTerminal/ec2575fb877d41c9a33d9bab2694ba47?source=relative 来 ...

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

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

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

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

  8. Java找N个数中最小的K个数,PriorityQueue和Arrays.sort()两种实现方法

    最近看到了 java.util.PriorityQueue.刚看到还没什么感觉,今天突然发现他可以用来找N个数中最小的K个数. 假设有如下 10 个整数. 5 2 0 1 4 8 6 9 7 3 怎么 ...

  9. [剑指offer]数组中最小的K个数,C++实现

    原创博文,转载请注明出处! http://github.com/wanglei5205 http://cnblogs.com/wanglei5205 # 题目 输入n个整数,找出其中最小的K个数.例如 ...

随机推荐

  1. Windows下配置Tomcat服务器

    Tomcat服务器是Apache开源基金会的一个项目,tomcat不仅能作为静态文件的服务器,也可以作为JSP/Servlet的web容器,而且使用广泛,性能也不错,那么下面来配置一个基本的基于tom ...

  2. 越狱后天气闪退 iPhone5天气闪退解决方法

    iPhone5天气闪退解决方法: 第一步:前往Cydia卸载AppSync; 第二步:通过iTools删除/var/mobile/Library/Caches/com.apple.mobile.ins ...

  3. MySQL和PHP基础考试错题回顾

    13.关于exit( )与die( )的说法正确的是( B) C A.当exit( )函数执行会停止执行下面的脚本,而die()无法做到 B.当die()函数执行会停止执行下面的脚本,而exit( ) ...

  4. sqlserver临时启用和关闭约束

    select  'ALTER TABLE ['  + b.name +  '] NOCHECK CONSTRAINT ' +  a.name +';' as  禁用约束   from  sysobje ...

  5. 禁随意改root密码

    lsattr 主要参数如表. -a 显示所有文件和目录,包括以"."为名称开头字符的额外内建,现行目录"."与上层目录"..". -d 显示 ...

  6. 第六步:Lucene查询索引(优化一)

    package cn.harmel.lucene; import java.io.IOException; import java.nio.file.Paths; import org.apache. ...

  7. hrbustoj 1179:下山(DFS+剪枝)

    下山Time Limit: 1000 MS Memory Limit: 65536 KTotal Submit: 271(111 users) Total Accepted: 129(101 user ...

  8. hdu 1465:不容易系列之一(递推入门题)

    不容易系列之一 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Sub ...

  9. poj 1236 scc强连通分量

    分析部分摘自:http://www.cnblogs.com/kuangbin/archive/2011/08/07/2130277.html 强连通分量缩点求入度为0的个数和出度为0的分量个数 题目大 ...

  10. cJSON: 一个用c写的一个简单好用的JSON解析器

    转自:http://blog.csdn.net/chenzhongjing/article/details/9188347 下载地址: http://sourceforge.net/projects/ ...