当前位置: 首页 > news >正文

[LeetCode]剑指 Offer 40. 最小的k个数

输入整数数组 arr ,找出其中最小的 k 个数。例如,输入 4、5、1、6、2、7、3、8 这 8 个数字,则最小的 4 个数字是 1、2、3、4。

示例 1:

输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]

示例 2:

输入:arr = [0,1,2,1], k = 1
输出:[0]

限制:

  • 0 <= k <= arr.length <= 10000
  • 0 <= arr[i] <= 10000

题解一:

	/**
     * 剑指 Offer 40. 最小的k个数     
     */
    public int[] getLeastNumbers(int[] arr, int k) {
    	// 排序后返回数组的前 k 个数即可
        Arrays.sort(arr);
        return Arrays.copyOf(arr, k);
    }

题解二:

利用 快速排序 算法(升序)基准数左边的数均小于基准数的特点,

对原数组进行快速排序,若在某一趟快排的过程中基准数左边(含基准数)的元素个数等于 k 则直接返回子数组即可(题目未要求返回的元素顺序)。

	/**
     * 剑指 Offer 40. 最小的k个数
     */
    public int[] getLeastNumbers(int[] arr, int k) {
        /*
         * 利用快速排序(升序)基准数左边的数均小于基准数的特点,
         * 对原数组进行快速排序,在快排的过程中若某一趟过程中基准数左边(含基准数)的元素个数等于 k 则直接返回子数组即可
         */
        return k >= arr.length ? arr : quickSort(arr, 0, arr.length - 1, k);
    }

    public int[] quickSort(int[] arr, int start, int end, int k) {
        int left = start;
        int right = end;
        // 每次快排选取最左边的数作为基准数
        int baseNum = arr[start];

        while (left < right) {
            // 从右往左寻找不大于基准数的数
            while (right > left && arr[right] >= baseNum) {
                right--;
            }
            // 从左往右寻找不小于基准数的数
            while (left < right && arr[left] <= baseNum) {
                left++;
            }
            int tmp = arr[left];
            arr[left] = arr[right];
            arr[right] = tmp;
        }

        // 移动基准数
        arr[start] = arr[left];
        arr[left] = baseNum;

        // 左序列比基准数小的元素个数大于 k,左序列继续快排
        if (left > k) {
            return quickSort(arr, start, left - 1, k);
        }
        // 左序列比基准数小的元素个数小于 k,右序列快排
        if (left < k) {
            return quickSort(arr, left + 1, end, k);
        }
        return Arrays.copyOf(arr, k);
    }

题解三:

  • 大顶堆(升序):每个父节点的值都大于或等于其左右孩子节点的值(并未要求左右孩子值的大小关系)

  • 小顶堆(降序):每个父节点的值都小于或等于其左右孩子节点的值(并未要求左右孩子值的大小关系)

题目要求找出数组中前 K 个小的数,因此用一个容量为 K 的大根堆,每次 poll 出最大的数,那堆中保留的就是前 K 小啦(注意不是小根堆!小根堆的话需要把全部的元素都入堆,时间复杂度是 O(NlogN) 而不是 O(NlogK)

此方法较快排慢,但 Java 中提供了现成的 PriorityQueue(默认小根堆),实现起来最为简单。

	/**
     * 剑指 Offer 40. 最小的k个数
     */
    public int[] getLeastNumbers(int[] arr, int k) {
        /*
         * 保持堆的大小为 K,遍历数组中的元素,遍历的时做如下判断:
         *  1. 若堆的大小小于 K,当前数字入堆
         *  2. 否则判断当前数字与大根堆堆顶元素的大小关系,如果当前数字比大根堆堆顶还大,这个数就直接跳过
         *  3. 反之先 poll 掉堆顶,再将该数字放入堆顶
         * 当遍历完数组中的元素时就可以保证留在大根堆中 K 个数是数组中最小的 K 个数
         */
        if (k <= 0 || arr.length == 0) {
            return new int[0];
        }
        // 默认是小根堆,实现大根堆需要重写比较器
        Queue<Integer> heap = new PriorityQueue<>((v1, v2) -> v2 - v1);
        for (int num : arr) {
            // 若堆的大小小于 K,当前数字入堆
            if (heap.size() < k) {
                heap.offer(num);
            } else if (num < heap.peek()) {
                // 当前数字比大根堆堆顶小,弹出堆顶元素,当前元素入堆
                heap.poll();
                heap.offer(num);
            }
        }

        // 返回堆中的元素即是数组中最小的 K 个数
        int[] res = new int[k];
        int idx = 0;
        for (int num : heap) {
            res[idx++] = num;
        }
        return res;
    }

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/zui-xiao-de-kge-shu-lcof

相关文章:

  • 知识分享|高企认定八大条件详细解读!
  • 薪资达十万、百万的居然是游戏建模
  • RT-thread 中CAN总线的应用
  • Flutter Widgets 之 RubyText
  • 生物素衍生物PC azide-PEG3-Biotin,1937270-46-6 相关性质分享
  • 前端技术选型
  • 前端知识5-jQuery
  • Stata绘制分类带可信区间的折线图
  • 全球与中国板上芯片LED行业发展规模及投资前景预测报告2022-2028年
  • 哪里有比Excel还好用的在线表单制作工具?
  • 使用sysctl调优Linux内核
  • charles劫持修改js文件
  • 机房服务器远程维护解决方案,解决机房安全问题刚刚好
  • 俄罗斯考虑购买700亿美元的“友好”国家外汇
  • 22牛客多校4 - Task Computing(相邻贪心,推式子倒序DP)
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • android高仿小视频、应用锁、3种存储库、QQ小红点动画、仿支付宝图表等源码...
  • iOS 颜色设置看我就够了
  • js算法-归并排序(merge_sort)
  • NLPIR语义挖掘平台推动行业大数据应用服务
  • nodejs:开发并发布一个nodejs包
  • React-redux的原理以及使用
  • SOFAMosn配置模型
  • 基于OpenResty的Lua Web框架lor0.0.2预览版发布
  • 数据库写操作弃用“SELECT ... FOR UPDATE”解决方案
  • 推荐一款sublime text 3 支持JSX和es201x 代码格式化的插件
  • 我的面试准备过程--容器(更新中)
  • Linux权限管理(week1_day5)--技术流ken
  • (4)事件处理——(7)简单事件(Simple events)
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (JS基础)String 类型
  • (webRTC、RecordRTC):navigator.mediaDevices undefined
  • (二)丶RabbitMQ的六大核心
  • (附源码)ssm智慧社区管理系统 毕业设计 101635
  • (四)Tiki-taka算法(TTA)求解无人机三维路径规划研究(MATLAB)
  • *++p:p先自+,然后*p,最终为3 ++*p:先*p,即arr[0]=1,然后再++,最终为2 *p++:值为arr[0],即1,该语句执行完毕后,p指向arr[1]
  • .net Signalr 使用笔记
  • .NET 设计一套高性能的弱事件机制
  • .Net高阶异常处理第二篇~~ dump进阶之MiniDumpWriter
  • .NET构架之我见
  • .NET中的Event与Delegates,从Publisher到Subscriber的衔接!
  • @ResponseBody
  • [ C++ ] template 模板进阶 (特化,分离编译)
  • []指针
  • [AutoSar NVM] 存储架构
  • [BUUCTF]-PWN:wustctf2020_number_game解析(补码,整数漏洞)
  • [BZOJ]4817: [Sdoi2017]树点涂色
  • [C++] sqlite3_get_table 的使用
  • [C语言]——函数递归
  • [iOS]Win8下iTunes无法连接iPhone版本的解决方法
  • [LeetCode] 19. 删除链表的倒数第 N 个结点
  • [Linux](16)网络编程:网络概述,网络基本原理,套接字,UDP,TCP,并发服务器编程,守护(精灵)进程
  • [MT8766][Android12] 取消WIFI热点超过10分钟没有连接自动关闭设定
  • [MySQL]数据库基础
  • [POJ 1915] Knight Moves