IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【LeetCode】剑指 Offer 40. 最小的k个数 -> 正文阅读

[数据结构与算法]【LeetCode】剑指 Offer 40. 最小的k个数

【LeetCode】剑指 Offer 40. 最小的k个数

一、笨比解法

选择排序变形

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        int[] res = new int [k];
        for(int i = 0; i < k; i++){
            int minIndex = i;
            for(int j = i; j < arr.length; j++){
                if(arr[minIndex] > arr[j]){
                    int temp = arr[minIndex];
                    arr[minIndex] = arr[j];
                    arr[j] = temp;
                }
            }
            res[i] = arr[minIndex];
        }
        return res;
    }
}
  • 时间复杂度为 O(k * n):k 为需要找的最小数的个数,n 为数组长度
  • 空间复杂度为 O(k):使用了大小为 k 的数组

二、堆排序

比较直观的想法是使用堆结数据结构来辅助的到最小的 k 个数。堆的性质是每次可以找出最大或最小的元素。我们可以使用一个大小为 k 的最大堆(大顶堆),将数组中的元素依次入堆,当堆的大小超过 k 时,便将多出的元素从堆顶弹出。我们以数组 [5,4,1,3,6,2,9],k = 3 为例展示元素入堆的过程,如下面动图所示:
在这里插入图片描述
这样,由于每次从堆顶弹出的数据都是堆中最大的,最小的 k 个元素一定会留在堆里。这样,把数组中的元素全部入堆之后,堆中剩下的 k 个元素就是最大的 k 个数了

注意在动画中,我们并没有画出堆的内部结构,因为这部分内容并不重要。我们只需要直到堆每次会弹出最大的元素即可。在写代码的时候,我们使用的也是库函数中的优先队列数据结构,如 Java 中的 PriorityQueue,若想实现堆的结构,请参考【Java数据结构与算法】第十一章

class Solution{
	public int[] getLeastNumbers(int[] arr, int k){
		if(k == 0) return new int[0];
		if(arr.length <= k) return arr;

		Queue<Integer> heap = new PriorityQueue<>(k,(i1,i2) -> Integer.compare(i2,i1));

		for(int i : arr){
			if(heap.size() == 0 || heap.size() < k || i < heap.peek()){
				heap.offer(i);
			}
			if(heap.size() > k){
				heap.poll();
			}
		}

		int[] res = new int[k];
		int i = 0;
		for(int j : heap){
			res[i++] = j;
		}

		return res;
	}
}
  • 时间复杂度为 O(nlogk),每个元素都需要进行一次入堆操作,入堆出堆的时间复杂度为 O(logk)
  • 空间复杂度为 O(k),使用了一个大小为 k 的堆

三、快速选择

题目只要求返回最小的 k 个数,对这 k 个数的顺序并没有要求。因此,只需要将数组划分为最小的 k 个数和其他数两部分即可,而快速排序的哨兵划分可完成此目标

根据快速排序原理,如果某次哨兵划分后基准数正好是第 k + 1 小的数字,那么此时基准数左边的所有数字便是题目所求的最小的 k 个数

根据此思路,考虑在每次哨兵划分后,判断基准数在数组中的索引是否等于 k,若 true 则直接返回此时数组的前 k 个数字即可

getLeastNumbers() 函数:

  1. 若 k 大于数组长度,则直接返回整个数组
  2. 执行并返回 quick_sort() 即可,quick_sort() 的功能不是排序整个数组,而是搜索并返回最小的 k 个数

哨兵划分:

  • 划分完毕后,基准数为 arr[i] ,左 / 右子数组区间分别为 [l,i-1],[i+1,r]

递归或返回:

  • 若 k < i,代表 k + 1 小的数字在左子数组中,则递归左子数组
  • 若 k > i,代表 k + 1 小的数字在右子数组中,则递归右子数组
  • 若 k = i,代表此时 arr[k] 即为第 k + 1 小的数字,则直接返回数组前 k 个数字即可
class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        if(k >= arr.length) return arr;
        return quickSort(arr,0,arr.length-1,k);
    }
    private static int[] quickSort(int[] arr, int l, int r, int k) {
        int i = l;
        int j = r;
        while(i < j){
            while(i < j && arr[j] >= arr[l]) j--;
            while(i < j && arr[i] <= arr[l]) i++;
            swap(arr,i,j);
        }
        swap(arr,i,l);
        if(i > k) quickSort(arr,l,i-1,k);
        if(i < k) quickSort(arr,i+1,r,k);
        return Arrays.copyOf(arr,k);
    }
    private static void swap(int[] arr,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}
  • 时间复杂度 O(n),其中 n 为数组元素数量,对于长度为 N 的数组执行哨兵划分操作的时间复杂度为 O(n)。每轮哨兵划分后根据 k 和 i 的大小关系选择递归,由于 i 分布的随机性,则向下递归子数组的平均长度为 n/2。因此平均情况下哨兵划分操作一共有 2n - 1(等比数列求和),即总体时间复杂度为 O(n)
  • 空间复杂度 O(logn):划分函数的平均递归深度为 O(logN)

总结

由于对于快排还没有到炉火纯青的地步,以及对堆排序比较陌生,我想出来的方法是使用选择排序,因为选择排序不需要将整个数组排序才能退出,选择排序即使中途退出,也能保证前 k 个数是最小且有序的数,这与题目只需要前 k 个数有序契合
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-08-06 10:05:03  更:2021-08-06 10:07:31 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 19:34:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码