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

一、题目描述

☆☆二、解法

方法1:基于快排的选择方法,即快排partition函数的应用。

Note: 针对本题来说,快排的枢纽点要随机取,否则极端测试用例,会导致退化为O(n^2)

方法2:基于堆排序的选择方法。

解法1:

class Solution {
    public int findKthLargest(int[] nums, int k) {
        int len = nums.length;
        int start = 0, end = len - 1;
        while (true){
            int pivotIndex = partition2(nums,start,end);
            if (pivotIndex == len - k) {
                return nums[pivotIndex];
            }else if (pivotIndex < len - k) {
                start = pivotIndex + 1;
            }else {
                end = pivotIndex - 1;
            }
        }
    }

    /**
     *  快排partition函数:返回pivot的index,使得左边的值都比他小,右边的值都比它大
     */
    public int partition1(int[] nums, int start, int end) {
        int pivot = nums[start];
        while (start < end) {
            while (start < end && nums[end] >= pivot) {
                end--;
            }
            swap(nums,start,end);
            while (start < end && nums[start] <= pivot) {
                start++;
            }
            swap(nums,start,end);
        }
        return start; // 返回枢纽所在的位置
    }

    /**
     *  快排partition函数的优化版本
     *      优化思路:采用替换而不是交换的方式进行操作
     */
    public int partition2(int[] nums, int start, int end) {
        // 随机在arr[start...end]的范围中, 选择一个数值作为标定点pivot
        // Math.random()产生[0,1)的double型随机数,
        // 区间[a,b]的随机数 -> Math.random*(b-a+1)+a
//        int pivot = nums[(int)Math.random()*(end-start+1) + start];
        int pivot = nums[start];
        while (start < end) {
            // 顺序很重要,要先从右往左找,如果右边的数比标准数大
            while (start < end && nums[end] >= pivot) {
                end--;
            }
            // 使用右边的数字替换左边的数
            nums[start] = nums[end];
            while (start < end && nums[start] <= pivot) {
                start++;
            }
            nums[end] = nums[start];
        }
        // 标准数归位
        nums[start] = pivot;
        return start;  // 返回枢纽所在的位置
    }
    public void swap(int[] nums, int a, int b) {
        int temp = nums[a];
        nums[a] = nums[b];
        nums[b] = temp;
    }
}

解法2:

class Solution {
    public int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> minHeap = new PriorityQueue<>();
        for (int num : nums) {
            minHeap.offer(num);
            if (minHeap.size() > k) {
                minHeap.poll(); // 每次移除的就是堆中最小的值
            }
        }
        return minHeap.peek();
    }
}

 

参考:

本题的多种解法见 通过 partition 减治 + 优先队列(Java、C++、Python)

 

posted @ 2020-12-06 17:38  不学无墅_NKer  阅读(103)  评论(0编辑  收藏  举报