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)