首页 > 技术文章 > 215. 数组中的第K个最大元素 + 快速排序 + 大根堆

GarrettWale 2021-02-18 21:39 原文

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

LeetCode-215

另一道类似的第k大元素问题:https://www.cnblogs.com/GarrettWale/p/14386862.html

题目详情

方法一:使用快速排序

package com.walegarrett.interview;

/**
 * @Author WaleGarrett
 * @Date 2021/2/17 22:24
 */

import java.util.Arrays;

/**
 * 题目描述:在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
 */

/**
 * 方法一:使用快速排序的思想
 */
public class LeetCode_215 {
    public int findKthLargest(int[] nums, int k) {
        return quickSort(nums, nums.length-k+1, 0, nums.length -1);
    }
    /**
     * 一趟排序,每一趟返回一个数的确定位置
     * @param arr
     * @param l
     * @param r
     * @return
     */
    int partition(int[] arr, int l, int r){
        int fix = arr[l];//需要确定arr[l]的位置
        while(l<r){
            while(arr[r] >= fix && l<r)
                r--;
            if(l<r){
                arr[l] = arr[r];
                l++;
            }
            while(arr[l] <= fix && l<r)
                l++;
            if(l<r){
                arr[r] = arr[l];
                r--;
            }
        }
        //最后才确定fix的位置
        arr[l] = fix;
        return l;
    }

    /**
     * 查找最小的k个数
     * @param arr
     * @param k
     * @param l
     * @param r
     */
    int quickSort(int[] arr, int k, int l, int r){
        int index = partition(arr, l, r);
        if(index == k-1){
            return arr[index];
        }else if(index <k-1){//找到的index个数小于k个,需要继续往右半部分递归查找
            return quickSort(arr, k, index+1, r);
        }else{
            return quickSort(arr, k, l, index-1);
        }
    }
}

方法二:使用大根堆排序--自定义堆

/**
 * 方法二:自定义大根堆
 */
class LeetCode_215_2 {
    public int findKthLargest(int[] nums, int k) {
        int heapSize = nums.length;
        createHeap(nums,heapSize);
        for(int i=nums.length-1;i>=nums.length-k-1;i--){
            swap(i,0,nums);
            heapAdjust(0,nums,--heapSize);
        }
        return nums[0];
    }

    /**
     * 构建大根堆:从非叶子结点开始从下往上构建大根堆
     * @param nums
     * @param heapSize
     */
    void createHeap(int[] nums,int heapSize){
        int len = heapSize;
        for(int i=len/2; i>=0; i--){
            heapAdjust(i, nums,heapSize);
        }
    }

    /**
     * 堆调整
     * @param root
     * @param nums
     * @param heapSize
     */
    void heapAdjust(int root,int[] nums,int heapSize){
        int lr = root*2+1, rr=root*2+2;
        int len = heapSize;
        int maxIndex = root;
        if(lr<len && nums[lr]>nums[maxIndex]){
            maxIndex = lr;
        }
        if(rr<len && nums[rr]>nums[maxIndex]){
            maxIndex = rr;
        }
        if(maxIndex!=root){
            swap(root,maxIndex,nums);
            heapAdjust(maxIndex,nums,heapSize);
        }
    }

    void swap(int i, int j, int[] nums){
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}

方法四:小顶堆

除了自己手撸堆排序,我们还可以使用java自带的优先队列,它也是实现了小顶堆。

class Solution {
    public int findKthLargest(int[] nums, int k) {
        // 维护一个小根堆
        PriorityQueue<Integer> que = new PriorityQueue<>();
        for(int num : nums){
            if(k > 0){
                que.offer(num);
                k--;
            }else{
                if(que.peek() < num){
                    que.poll();
                    que.offer(num);
                }
            }
        }
        return que.peek();
    }
}

推荐阅读