博客
关于我
剑指 Offer 40. 最小的k个数(简单)
阅读量:706 次
发布时间:2019-03-21

本文共 3311 字,大约阅读时间需要 11 分钟。

思路

为了实现获取前k小的数,我们可以采用三种不同的方法:使用Java的Arrays.sort、快速排序配合二分、以及使用优先队列(大根堆)。每一种方法都有其独特的效率和适用场景,为开发者提供选择。

代码示例

方法一:使用Java的Arrays.sort

这个方法简单直接,但需要注意,当k小于等于数组长度时,可以直接使用Arrays.sort并截取前k个元素。代码如下:

import java.util.Arrays;public class Solution {    public int[] getLeastNumbers(int[] arr, int k) {        if (k <= 0) {            return new int[0];        }        Arrays.sort(arr);        int[] res = new int[k];        System.arraycopy(arr, 0, res, 0, k);        return res;    }}

方法二:快速排序配合二分法

这种方法体现了一种高效的分治策略。首先确定基准点,然后划分数组区域进行递归排序,并根据k的位置调整范围。实现细节如下:

public class Solution {    public int[] getLeastNumbers(int[] arr, int k) {        if (k <= 0 || arr.length <= 0) {            return new int[0];        }        if (k >= arr.length) {            return arr;        }        return quickSort(arr, k, 0, arr.length - 1);    }    private int[] quickSort(int[] arr, int k, int left, int right) {        int l = left;        int r = right;        while (l < r) {            while (l < r && arr[r] >= arr[l]) {                r--;            }            while (l < r && arr[l] <= arr[l + 1]) {                l++;            }            swap(arr, l, r);            swap(arr, l, l + 1);        }                if (k <= l) {            return Arrays.copyOf(arr, k);        } else {            int[] leftPart = quickSort(arr, k, 0, l - 1);            return merge(leftPart, arr, k, l, r);        }    }    private void swap(int[] arr, int i, int j) {        int temp = arr[i];        arr[i] = arr[j];        arr[j] = temp;    }    private int[] merge(int[] left, int[] arr, int k, int l, int r) {        int[] rightPart = Arrays.copyOf(arr, r - l + 1);        int count = 0;        int i = 0;        int j = 0;        int[] result = new int[k];        while (i < left.length && count < k) {            if (left[i] < rightPart[j]) {                result[count++] = left[i];                i++;            } else {                result[count++] = rightPart[j];                j++;                count++;                if (count == k) {                    return result;                }            }        }        return result;    }}

方法三:使用优先队列(大根堆)

优先队列适合处理需要频繁获取最小值的场景。这里使用大根堆来维护前k小的数,确保堆顶是当前最小的。实现代码如下:

import java.util.*;public class Solution {    public int[] getLeastNumbers(int[] arr, int k) {        if (k <= 0 || arr.length == 0) {            return new int[0];        }        PriorityQueue
heap = new PriorityQueue<>((v1, v2) -> v2 - v1); for (int num : arr) { if (heap.size() < k) { heap.add(num); } else { if (num < heap.peek()) { heap.remove(); heap.add(num); } } } int[] res = new int[k]; for (int i = 0; i < k; i++) { res[i] = heap.remove(); } return res; }}

分解方法

方法二详解

  • 基准点选择:快速排序的基准点从数组的左右两端开始选择,这可以提高排序效率。
  • Recursive Partition:将数组划分为两部分,左部分比基准点小,右部分比基准点大。
  • k的判断:根据k的位置决定是否在左边或右边递归,这保证了只处理必要的部分。
  • Merge:合并两个有序的子数组,确保整个结果数组有序,从中截取k个最小的数。
  • 方法三详解

  • 初始化大根堆:默认优先队列使用小根堆,所以需要自定义比较器,使其作为大根堆来使用。
  • 处理元素:将数组中的每个元素添加到堆中,如果堆大小超过k,则替换掉较大的元素。
  • 提取结果:最终从堆中取出前k个最小的数,构建结果数组。
  • 复杂度分析

    方法一

    • 时间复杂度:O(N log N)
    • 空间复杂度:O(N)

    方法二

    • 时间复杂度:O(N)(假设k在数组的前后附近,为最优情况)
    • 空间复杂度:O(N)

    方法三

    • 时间复杂度:O(N log k)
    • 空间复杂度:O(k)

    通过对比,可以根据不同的需求选择最合适的方法。总的来说,方法二和方法三在不同数据规模和k值时表现优异。

    转载地址:http://flzrz.baihongyu.com/

    你可能感兴趣的文章
    OpenCV与AI深度学习 | 基于YoloV11自定义数据集实现车辆事故检测(有源码,建议收藏!)
    查看>>
    OpenCV与AI深度学习 | 基于YOLOv8 + BotSORT实现球员和足球检测与跟踪 (步骤 + 源码)
    查看>>
    OpenCV与AI深度学习 | 基于YOLOv8实现高级目标检测和区域计数
    查看>>
    VS2003 Front Page Server Extension
    查看>>
    OpenCV与AI深度学习 | 基于YOLOv8的停车对齐检测
    查看>>
    OpenCV与AI深度学习 | 基于YoloV8的药丸/片剂类型识别
    查看>>
    OpenCV与AI深度学习 | 基于YOLO和EasyOCR从视频中识别车牌
    查看>>
    OpenCV与AI深度学习 | 基于图像处理的火焰检测算法(颜色+边缘)
    查看>>
    OpenCV与AI深度学习 | 基于拉普拉斯金字塔实现图像融合(步骤 + 代码)
    查看>>
    OpenCV与AI深度学习 | 基于改进YOLOv8的景区行人检测算法
    查看>>
    OpenCV与AI深度学习 | 基于机器视觉的磁瓦表面缺陷检测方案
    查看>>
    OpenCV与AI深度学习 | 基于深度学习的轮胎缺陷检测系统
    查看>>
    OpenCV与AI深度学习 | 如何使用YOLO-World做目标检测
    查看>>
    OpenCV与AI深度学习 | 如何使用YOLOv9分割图像中的对象
    查看>>
    OpenCV与AI深度学习 | 如何使用YOLOv9检测图片和视频中的目标
    查看>>
    OpenCV与AI深度学习 | 如何在 Docker 容器中使用 GPU
    查看>>
    OpenCV与AI深度学习 | 实战 | OpenCV中更稳更快的找圆方法--EdgeDrawing使用演示(详细步骤 + 代码)
    查看>>
    OpenCV与AI深度学习 | 实战 | OpenCV传统方法实现密集圆形分割与计数(详细步骤 + 代码)
    查看>>
    OpenCV与AI深度学习 | 实战 | OpenCV实现扫描文本矫正应用与实现详解(附源码)
    查看>>
    OpenCV与AI深度学习 | 实战 | YOLOv10模型微调检测肾结石并提高准确率
    查看>>