题目
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。
示例 1:
输入: [3,2,1,5,6,4], k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4
提示:
1 <= k <= nums.length <= 10^5
-10^4 <= nums[i] <= 10^4
思路1
优先级队列,取出前k大个元素,第k大个元素就在最后。时间复杂度O(nlogk)。
思路2
直接将数组排序,第k大个元素索引就是n - k。时间复杂度O(nlogn)。
思路3
快排分区partition思想,当分区函数返回的索引值 = n - k,该分区元素就是要找的元素。时间复杂度O(n)。

代码
class Solution {
/**
* 快速排序的partition分区思想解决第k大元素问题
* @param nums
* @param k
* @return
*/
public int findKthLargest(int[] nums, int k) {
//第k大元素的索引为n - k
//[1,2,3,4,5]第2大元素4对应的索引为5 - 2 = 3
return findKthLargestInternal(nums, 0, nums.length - 1, nums.length - k);
}
/**
* 在nums[l...r]找到索引为k元素
* @param nums
* @param l
* @param r
* @param k
* @return
*/
private int findKthLargestInternal(int[] nums, int l, int r, int k) {
if(l > r) {
//空区间
return -1;
}
int p = partition(nums, l, r);
if(p == k) {
//此时索引p对应的元素恰好就是要查找的元素
return nums[p];
} else if(k > p) {
//在右半区间接着找
return findKthLargestInternal(nums, p + 1, r, k);
}
//此时k < p,在左半区间找
return findKthLargestInternal(nums, l, p - 1, k);
}
/**
* 分区函数
* @param nums
* @param l
* @param r
* @return
*/
private int partition(int[] nums, int l, int r) {
//默认选择第一个元素作为分区点
int v = nums[l];
//i是当前处理的元素
//arr[l + 1...j] < v
//最开始没有元素 < v
int j = l;
//arr[j + 1...i) >= v也是空区间
for (int i = l + 1; i <= r; i++) {
if(nums[i] < v) {
swap(nums, j + 1, i);
j++;
}
}
//j对应 <v 的最后一个元素
swap(nums, l, j);
return j;
}
/**
* 交换三连操作
* @param nums
* @param i
* @param j
*/
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
文章介绍了如何在给定整数数组nums中找到第k个最大的元素,提出了三种方法:使用优先级队列(时间复杂度O(nlogk)),直接排序(时间复杂度O(nlogn)),以及基于快速排序的分区思想(时间复杂度O(n))。并提供了使用快速排序分区策略的Java代码实现。
495

被折叠的 条评论
为什么被折叠?



