• 【LeetCode热题100】--215.数组中的第K个最大元素


    215.数组中的第K个最大元素

    image-20231014101954753

    本题主要是返回数组排序之后的倒数第k个位置

    方法一:基于快速排序

    思路和算法

    我们可以用快速排序来解决这个问题,先对原数组排序,再返回倒数第 k 个位置,这样平均时间复杂度是 O(nlog⁡n),但其实我们可以做的更快

    首先我们来回顾一下快速排序,这是一个典型的分治算法。我们对数组 a[l⋯r]做快速排序:

    • 分解: 将数组 a[l⋯r]「划分」成两个子数组 a[l⋯q−1]、a[q+1⋯r],使得 a[l⋯q−1]中的每个元素小于等于 a[q]a[q]a[q],且 a[q] 小于等于 a[q+1⋯r] 中的每个元素。其中,计算下标 q也是「划分」过程的一部分。
    • 解决: 通过递归调用快速排序,对子数组 a[l⋯q−1] 和 a[q+1⋯r]进行排序。
    • 合并: 因为子数组都是原址排序的,所以不需要进行合并操作,a[l⋯r]已经有序。
    • 上文中提到的 「划分」 过程是:从子数组 a[l⋯r]中选择任意一个元素 x作为主元,调整子数组的元素使得左边的元素都小于等于它,右边的元素都大于等于它, x 的最终位置就是 q。

    由此可以发现每次经过「划分」操作后,我们一定可以确定一个元素的最终位置,即 x的最终位置为 q,并且保证 a[l⋯q−1] 中的每个元素小于等于 a[q],且 a[q] 小于等于 a[q+1⋯r]中的每个元素。所以只要某次划分的 q 为倒数第 k 个下标的时候,我们就已经找到了答案。 我们只关心这一点,至于 a[l⋯q−1]和 a[q+1⋯r]是否是有序的,我们不关心

    因此我们可以改进快速排序算法来解决这个问题:在分解的过程当中,我们会对子数组进行划分,如果划分得到的 q 正好就是我们需要的下标,就直接返回 a[q];否则,如果 q比目标下标小,就递归右子区间,否则递归左子区间。这样就可以把原来递归两个区间变成只递归一个区间,提高了时间效率。这就是「快速选择」算法。

    class Solution {
        int quickselect(int[] nums, int l,int r,int k) {
            if(l == r ){
                return nums[k];
            }
            int x = nums[l],i = l - 1,j = r + 1;
            while(i < j){  //下面过程就是进行快速排序
                do {
                    i++;
                }while(nums[i] < x);  //找到左区间大于x的位置
                do{
                    j--;
                }while(nums[j] > x);  //找到右区间小于x的位置
                if(i<j){   //将两者进行交换
                    int tmp = nums[i];
                    nums[i] =  nums[j];
                    nums[j] = tmp;
                }
            }
            if(k<=j){  //x比目标下标大,递归左子区间
                return quickselect(nums,l,j,k);
            }else{   //x比目标下表小,递归右子区间
                return quickselect(nums,j+1,r,k);
            }
            
        }
        public int findKthLargest(int[] _nums,int k){
            int n = _nums.length;
            //第K个最大及第n-k个大的(从0开始)
            return quickselect(_nums, 0, n-1, n-k);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    方法二:基于堆排序

    我们也可以使用堆排序来解决这个问题——建立一个大根堆,做 k−1k - 1k−1 次删除操作后堆顶元素就是我们要找的答案。在很多语言中,都有优先队列或者堆的的容器可以直接使用

    class Solution {
        public int findKthLargest(int[] nums,int k){
            int headSize = nums.length;
            buildMaxHeap(nums,headSize);
            for(int i = nums.length - 1; i>= nums.length-k+1; --i){
                swap(nums,0,i);
                --headSize;
                maxHeapify(nums,0,headSize);
            }
            return nums[0];
        }
    
        public void buildMaxHeap(int[] a,int headSize){
            for(int i = headSize/2; i>=0;--i){
                maxHeapify(a,i,headSize);
            }
        }
    
        public void maxHeapify(int[] a,int  i ,int headSize){
            int l = i * 2 + 1,r = i * 2 + 2,largest = i;
            if(l<headSize && a[l] > a[largest]){
                largest = l;
            }
            if(r < headSize && a[r] > a[largest]){
                largest = r;
            }
            if(largest != i){
                swap(a,i,largest);
                maxHeapify(a,largest,headSize);
            }
        }
        public void swap(int[] a,int i ,int j){
            int tmp = a[i];
            a[i] = a[j];
            a[j] = tmp;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
  • 相关阅读:
    redis字典
    负载均衡式的在线OJ系统
    C语言的offsetof宏模拟和用宏实现交换奇偶位
    面试官不讲武德,产品经理如何“耗子尾汁”?
    Android摄像头横屏的时候_人脸预览横向显示_问题解决---Android原生开发工作笔记164
    重置Jetson设备的Ubuntu密码:通过挂载根目录到另一个Linux系统
    C++ Primer学习笔记-----第三章:字符串、向量、数组
    Python深度学习实战-基于Sequential方法搭建BP神经网络实现分类任务(附源码和实现效果)
    顶刊TPAMI 2022!基于不同数据模态的行为识别:最新综述
    Spring Security 简单token配置
  • 原文地址:https://blog.csdn.net/qq_46656857/article/details/133822826