最小的k个数

  • 题目:输入n个整数,找出其中最小的k个数,例如输入4,5,6,7,8,9这六个数字,则最小的4个是4,5,6,7
方案一
  • 还是最直观的方法,先排序,最快的是快排O(nlog2n),然后遍历前面k个数组,得到我们需要的答案,这个最简单方案应该有更优实现
方案二
  • 题意,我们需要找出最小的k个数字,还是从快排的思路收到启发
  • 我们同样基于快速排序,但是只找出第k个大的数字
  • 因为快排过程中会将比基准值小的放到 之前,比基准值大的放到后面,因此只需要找到第k个大的数字,在之前的数就是我们需要的数
  • 基于如上分析有如下代码:
/*** 找出数组中最小的K个数** @author liaojiamin* @Date:Created in 10:18 2021/6/16*/
public class GetLeastNumbers {public static void main(String[] args) {Integer[] arrayData = new Integer[20];Random random = new Random();for (int i = 0; i < 20; i++) {arrayData[i] = random.nextInt(50);System.out.print(arrayData[i]+",");}System.out.println();Integer[] newArray = getLeastNumbers(arrayData, 10);for (Integer integer : newArray) {System.out.print(integer+",");}}/*** 按快速排序思路,找到第k个大的数,将小的放k前面* 将大的放k后,得到数组中最小的k个数就是下标是0~k的所有数*/public static Integer[] getLeastNumbers(Integer[] array, Integer key) {if (array == null || array.length <= 0 || array.length < key) {return new Integer[]{};}if (array.length == key) {return array;}return quickSort(array, 0, array.length-1, key);}public static Integer[] quickSort(Integer[] array, Integer left, Integer right, Integer key) {if (left < right) {Integer middle = quickSortSwap(array, left, right);if (middle == key) {return Arrays.copyOfRange(array, 0, key);}quickSort(array, left, middle - 1, key);quickSort(array, middle + 1, right, key);}return Arrays.copyOfRange(array, 0, key);}public static Integer quickSortSwap(Integer[] array, Integer left, Integer right) {if (left < right) {Integer position = array[left];while (left < right) {while (left < right && array[right] > position) {right--;}if (left < right) {array[left] = array[right];left++;}while (left < right && array[left] < position) {left++;}if(left < right){array[right] = array[left];right --;}}array[left] = position;}return left;}
}
  • 基于快排的方案是有限制的,因为我们需要修改输入的数组,最后的顺序是变化的,如果要求不能修改输入的参数,我们是否有其他方案。
方案三
  • 既然不能修改原值,那么我们复制一个我们需要的值,还是空间换时间的做法
  • 我们建一个原数组大小的容器用来存储,接着在容器中找出最小的k个数
  • 本次我们需要的存储的特点是能快速的找到最小值,这样重复查找k次最小值,就能得到结果
  • 如果我们用二叉查找树来实现这个容器,那么我们每次查询的时间复杂度是O(logn),也就是层高度,那么k次查询就是O(klogn)
  • 但是还有其他变种的二叉查找树二叉堆中对小堆,之前文章:数据结构与算法–二叉堆(最大堆,最小堆)实现及原理对最大堆,最小堆的实现有详细的解释
  • 最小堆的特点在于能在O(1)时间内找到最小值,就是二叉堆的根节点
  • 并且二叉堆的结构特性就在于能够快速的查询,我们将所有数据构造成一个最小堆,然后经k次O(1)的操作,就能得到结果
  • 经如上分析有如下代码:
/*** 找出数组中最小的K个数** @author liaojiamin* @Date:Created in 10:18 2021/6/16*/
public class GetLeastNumbers {public static void main(String[] args) {Integer[] arrayData = new Integer[20];Random random = new Random();for (int i = 0; i < 20; i++) {arrayData[i] = random.nextInt(50);System.out.print(arrayData[i]+",");}System.out.println();Integer[] heapArray = getLeastNumbersByBinaryHeapMax(arrayData, 10);for (int i = 0; i < heapArray.length; i++) {System.out.print(heapArray[i]+",");}}/*** 利用二叉堆,最小堆的结构特性,构建最小堆后,每次去跟节点都是最小的节点* 循环取k个最小堆中根元素,得到我们的结果* */public static Integer[] getLeastNumbersByBinaryHeapMax(Integer[] array, Integer key){if (array == null || array.length <= 0 || array.length < key) {return new Integer[]{};}if (array.length == key) {return array;}Integer size = (array.length + 2 )*11/10;BinaryHeap binaryHeap = new BinaryHeap(size);for (int i = 0; i < array.length; i++) {binaryHeap.insert(new AnyType(array[i]));}Integer[] result = new Integer[key];for (Integer i = 0; i < key; i++) {result[i] = Integer.valueOf(binaryHeap.deleteMin().getElement().toString());}return result;}
}

方案四

  • 如上最小堆的实现中虽然找最小值都是O(1),但是在构造最小堆的过程中我们需要O(logn)的时间复杂度,如果题目要是海量数据,其实我们也可以用最大堆
  • 我们可以用k个元素的最大堆,当堆满后,每次读入原数组中一个数据,与最大数据比较(O(1)时间)
  • 如果比最大数据要小,我们删除最大数据,插入当前值,直到整个数组遍历完
  • 此时得到的最大堆中k个数据就是我们需要的数据
  • 这种方案可以用来处理海量数据时候内存占用过多的问题。
  • 海量数据情况下,空间复杂度O(k)的实现方式如下:
/*** 找出数组中最小的K个数** @author liaojiamin* @Date:Created in 10:18 2021/6/16*/
public class GetLeastNumbers {public static void main(String[] args) {Integer[] arrayData = new Integer[20];Random random = new Random();for (int i = 0; i < 20; i++) {arrayData[i] = random.nextInt(50);System.out.print(arrayData[i]+",");}System.out.println();Integer[] maxArray = getLeastNumberByBinaryHeapMax(arrayData, 10);for (Integer integer : maxArray) {System.out.print(integer+",");}}/*** 利用二叉堆,最大堆,处理海量数据情况下获取前k个最小的数据* */public static Integer[] getLeastNumberByBinaryHeapMax(Integer[] array, Integer key){if (array == null || array.length <= 0 || array.length < key) {return new Integer[]{};}if (array.length == key) {return array;}Integer size = (array.length+2)*11/10;BinaryHeapMax binaryHeapMax = new BinaryHeapMax(size);for (int i = 0; i < array.length; i++) {AnyType anyType = new AnyType(array[i]);if(binaryHeapMax.heapSize() >= key){Integer heapMax =  Integer.valueOf(binaryHeapMax.findMax().getElement().toString());if(array[i] < heapMax){binaryHeapMax.deleteMax();binaryHeapMax.insert(anyType);}}else {binaryHeapMax.insert(anyType);}}AnyType[] anyTypes = binaryHeapMax.getAppHeapData();Integer[] result = new Integer[key];for (int i = 0; i < anyTypes.length; i++) {result[i] = Integer.valueOf(anyTypes[i].getElement().toString());}return result;}
}
解法对比
  • 第一种方案直接排序遍历平均时间复杂度是O(nlog2n),比第二种思路上更容易理解,但是同时也有明显的限制会修改入参数组
  • 第二种解法,也是基于快排思路,但是可以在中间退出,因此时间复杂度小于O(nlog2n),同样也会修改入参数组
  • 第三种方法,最小堆的方式,先构建最小堆,在读取,这种有两个明显优点,一个是没有修改输入的数据,因为我们只是读取入参数组中的数字,所有写操作都是在最小堆中完成,二是解法简单,缺点也明显,时间复杂度更大,构建时候需要insert,n次,每次insert的平均时间复杂度是O(logn),因此是O(nlogn)
  • 第四种算法适合海量数据的输入,如果题目要求的是海量数数据中找k个数,内存的大小限制,不可能全读取如内存,这时候,我们只一次读取一个数据进内存,只要求内存容纳的下最大堆中的k个数据即可,能有效解决n很大,k很小的情况,时间复杂度也是O(nlogk)

上一篇:数据结构与算法–两个链表中第一个公共节点
下一篇:数据结构与算法–数字在排序数组中出现次数

数据结构与算法--最小的k个数相关推荐

  1. 常考数据结构与算法:最小的k个数

    题目描述 输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,. 题目解答 使用小根堆 将n个元素全放进小根堆,再一个一个的弹出来, ...

  2. 编程算法 - 最小的k个数 红黑树 代码(C++)

    最小的k个数 红黑树 代码(C++) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 输入n个整数, 找出当中的最小k个数. 使用红黑树(multiset) ...

  3. 数据结构与算法--二叉树第k个大的节点

    二叉树第k个大的节点 二叉树文章列表: 数据结构与算法–面试必问AVL树原理及实现 数据结构与算法–二叉树的深度问题 数据结构与算法–二叉堆(最大堆,最小堆)实现及原理 数据结构与算法–二叉查找树转顺 ...

  4. 窥探算法之美妙——寻找数组中最小的K个数python中巧用最大堆

    原文发表在我的博客主页,转载请注明出处 前言 不论是小算法或者大系统,堆一直是某种场景下程序员比较亲睐的数据结构,而在python中,由于数据结构的极其灵活性,list,tuple, dict在很多情 ...

  5. 伍六七带你学算法 入门篇-最小的k个数

    java面试题-最小的k个数 难度-简单 输入整数数组 arr ,找出其中最小的 k 个数.例如,输入4.5.1.6.2.7.3.8这8个数字,则最小的4个数字是1.2.3.4. 示例 1: 输入:a ...

  6. c语言从4个整数中找最小的数,编程之法:面试和算法心得(寻找最小的k个数)...

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

  7. 【算法】最小的K个数

    题目描述 给定一个数组,找出其中最小的K个数.例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4.如果K>数组的长度,那么返回一个空的数组 示例1 输入 [ ...

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

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

  9. 【算法】剑指 Offer 40. 最小的k个数 【重刷】

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

最新文章

  1. Python_Statsmodels包_时间序列分析_ARIMA模型
  2. 最炫国漫《雾山五行》用 Python 了解一下到底有多优秀
  3. 学霸情侣一起投身国防事业,爱情和优秀同时发生了…
  4. Linux进阶之路———— RPM 与 YUM 包管理
  5. jframe运行和预览大小不一样_在泉州楼市中12个热门置业板块中,购房竞争压力大小各不一样...
  6. java 文曲星猜数字,「3D跨度表」文曲星中的猜数字游戏,要猜一个四位数,有什么通用公式?...
  7. mysql二进制日志开启方法_mysql中如何开启binlog?开启二进制日志文件?binary log?
  8. Android Toolbar
  9. 什么是 jsp,什么是Servlet?jsp 和Servlet 有什么区别?
  10. 二进制转八进制公式计算机,二进制转八进制算法(二进制与八进制的互相转换方法)...
  11. React的消息订阅全过程
  12. c++获取umg ue_[UE4]UMG widget Property Binding(属性绑定),事件触发蓝图函数和C++函数...
  13. #!/bin/bash和#!/bin/sh是什么意思以及区别
  14. uboot介绍:介绍uboot的基本概念、用法和实现方式
  15. Object Detection in 20 years:A Survey 整理
  16. 支持多线程的Redis 6.0终于发布了!
  17. 北京联通天邑TEWA-800E光猫改桥接
  18. 蚁群算法解决TSP问题(2#JAVA代码+详细注释+对比动态规划【JAVA】)
  19. 面向对象开发方法,Coad方法、Booch方法和OMT方法及UML
  20. Perl——正则表达式

热门文章

  1. C++编译之提示ld: can‘t open output file for writing: test1, errno=21 for architecture x86_64
  2. LeetCode之Add Digits
  3. Android之开源框架NineOldAndroids动画库
  4. 【python opencv 计算机视觉零基础到实战】二、 opencv文件格式与摄像头读取
  5. 在计算机技术方面用英语怎么说,“计算机应用技术”用英语怎么说?
  6. 光线在传播过程中是否会有变化?可以通过镜子接力的方式抵达目的地吗!?...
  7. 两点之间直线只有一条,曲线却有无数条,哪条才是最短的?
  8. 什么就像谈恋爱一样?
  9. 男生的哪个“不要”是真的不要?
  10. 颠覆传统,仅银行卡大小充电宝,10000mAh可登机,手机党出门随身必备!