题目: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. ext上传文件到mysql上

    不废话,上代码: controller如下: /** * 上传附件 * @param request * @param baseBlob * @param response */ @RequestMa ...

  2. WebSocket技术

    webSocket技术 在html5技术革新中,加入了WebSocket技术 1.webSocket实际是TCP连接 webSocket在最初将发送http连接请求到服务器端, 但是在header中加 ...

  3. GLSL Entry point not found

    解决方案: 在引用OpenGL的头文件 #include <GL/glew.h>#include <GL/glut.h> 前添加 #define GLUT_DISABLE_AT ...

  4. Human Gene Functions(poj 1080)

    题目大意是:给定两组DNA序列,要你求出它们的最大相似度 每个字母与其他字母或自身和空格对应都有一个打分,求在这两个字符串中插入空格,让这两个字符串的匹配分数最大 /* 思路是很好想的,设f[i][j ...

  5. js prototype

    1 原型法设计模式 在.Net中可以使用clone()来实现原型法 原型法的主要思想是,现在有1个类A,我想要创建一个类B,这个类是以A为原型的,并且能进行扩展.我们称B的原型为A. 2 javasc ...

  6. linux中断申请之request_threaded_irq

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=21977330&id=3755609 在linux里,中断处理分 ...

  7. 会员制实现C2B定制有机农产品,被中粮我买投资的良食网这样卖有机生鲜

    前几天,中粮我买网战略投资了位于深圳的有机生鲜自营平台良食网,宣布双方将会在供应链上展开合作.然而良食网对大家来说还是比较陌生的,为此36氪专访了良食网的创始人唐忠. 良食网成立于2011年,是一家以 ...

  8. Gym 100650H Two Ends DFS+记忆化搜索

    Problem H: Two EndsIn the two-player game “Two Ends”, an even number of cards is laid out in a row. ...

  9. 解决 Agent admitted failure to sign using the key 问题 with ssh

    之前如果建立 ssh 连接,只要將公鑰複製到 ~/.ssh/authorized_keys 就可以利用金鑰登入而不需要建立密碼. 現在的 ssh 使用同樣的方法會出現錯誤訊息 Agent admitt ...

  10. Struts2拦截器原理以及实例

    一.Struts2拦截器定义 1. Struts2拦截器是在访问某个Action或Action的某个方法,字段之前或之后实施拦截,并且Struts2拦截器是可插拔的,拦截器是AOP的一种实现. 2. ...