文章目录
-
-
- [1. 题目链接](#1. 题目链接)
- [2. 题目大意](#2. 题目大意)
- [3. 示例](#3. 示例)
- [4. 解题思路](#4. 解题思路)
- [5. 参考代码](#5. 参考代码)
-
1. 题目链接
215. 数组中的第K个最大元素 - 力扣(LeetCode)
2. 题目大意
描述:给定一个未排序的整数数组 nums 和一个整数 k。
要求:返回数组中第 k 个最大的元素。
说明:
- 要求使用时间复杂度为 O(n) 的算法解决此问题。
- 1≤k≤nums.length≤105。
- −104≤nums[i]≤104。
3. 示例
java
输入: [3,2,1,5,6,4], k = 2
输出: 5
java
输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4
4. 解题思路
使用快速排序在每次调整时,都会确定一个元素的最终位置,且以该元素为界限,将数组分成了左右两个子数组,左子数组中的元素都比该元素小,右子数组中的元素都比该元素大。
这样,只要某次划分的元素恰好是第 kk 个下标就找到了答案。并且我们只需关注第 kk 个最大元素所在区间的排序情况,与第 kk 个最大元素无关的区间排序都可以忽略。这样进一步减少了执行步骤。
5. 参考代码
java
import java.util.Random;
public class Solution {
private Random random = new Random();
// 随机哨兵划分:从 nums[low: high + 1] 中随机挑选一个基准数,并进行移位排序
private int randomPartition(int[] nums, int low, int high) {
// 随机挑选一个基准数
int i = random.nextInt(high - low + 1) + low;
// 将基准数与最低位互换
swap(nums, i, low);
// 以最低位为基准数,然后将数组中比基准数大的元素移动到基准数右侧,比它小的元素移动到基准数左侧。最后将基准数放到正确位置上
return partition(nums, low, high);
}
// 哨兵划分:以第 1 位元素 nums[low] 为基准数,然后将比基准数小的元素移动到基准数左侧,将比基准数大的元素移动到基准数右侧,最后将基准数放到正确位置上
private int partition(int[] nums, int low, int high) {
// 以第 1 位元素为基准数
int pivot = nums[low];
int i = low, j = high;
while (i < j) {
// 从右向左找到第 1 个小于基准数的元素
while (i < j && nums[j] >= pivot) {
j--;
}
// 从左向右找到第 1 个大于基准数的元素
while (i < j && nums[i] <= pivot) {
i++;
}
// 交换元素
swap(nums, i, j);
}
// 将基准数放到正确位置上
swap(nums, j, low);
return j;
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
private int quickSort(int[] nums, int low, int high, int k, int size) {
if (low < high) {
// 按照基准数的位置,将数组划分为左右两个子数组
int pivotIndex = randomPartition(nums, low, high);
if (pivotIndex == size - k) {
return nums[size - k];
}
if (pivotIndex > size - k) {
return quickSort(nums, low, pivotIndex - 1, k, size);
}
if (pivotIndex < size - k) {
return quickSort(nums, pivotIndex + 1, high, k, size);
}
}
return nums[size - k];
}
public int findKthLargest(int[] nums, int k) {
int size = nums.length;
return quickSort(nums, 0, nums.length - 1, k, size);
}
}