1.问题描述
给定整数数组 nums
和整数 k
,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k
个最大的元素,而不是第 k
个不同的元素。
2.测试用例
示例 1
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
3.提示
1 <= k <= nums.length <= 104
-104 <= nums[i] <= 104
4.代码
1.基于堆排序
code
/**
* 基于堆排序
*
* @param nums nums
* @param k k
* @return res
*/
public int findKthLargestWithBigHeapSort(int[] nums, int k) {
int n = nums.length;
int heapSize = n;
//构建大顶堆
buildBigHeapify(nums, heapSize);
//删除第 n - k个元素
for (int i = n - 1; i > n - k; i--) {
exchangeArrayEle(nums, 0, i);
heapSize--;
maxHeapfiy(nums, 0, heapSize);
}
//返回堆顶即可
return nums[0];
}
/**
* 构建大顶堆
* @param nums 数组
* @param heapSize 堆大小
*/
private void buildBigHeapify(int[] nums, int heapSize) {
for (int i = heapSize / 2 - 1; i >= 0; i--) {
//递归构建
maxHeapfiy(nums, i, heapSize);
}
}
/**
* 构建大顶堆
* @param nums 数组
* @param top 堆元素
* @param heapSize 堆大小
*/
private void maxHeapfiy(int[] nums, int top, int heapSize) {
int left = top * 2 + 1;
int right = top * 2 + 2;
int largest = top;
if (right < heapSize && nums[right] > nums[largest]) {
largest = right;
}
if (left < heapSize && nums[left] > nums[largest]) {
largest = left;
}
if (top != largest) {
exchangeArrayEle(nums, top, largest);
maxHeapfiy(nums, largest, heapSize);
}
}
/**
* 交换数组元素
* 临时变量法
*
* @param nums 数组
* @param i 待交换元素i
* @param j 待交换元素j
*/
public static void exchangeArrayEle(int[] nums, int i, int j) {
Assert.assertNotNull(nums);
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
复杂度
* 时间 O(nlogn)
* 空间 O(logn)
2.基于快速选择排序
code
/**
* 基于快速选择排序
* 时间 O(n) 证明过程可以参考《算法导论》9.2
* 空间 O(nlongn)
*
* @param nums nums
* @param k k
* @return res
*/
public int findKthLargestWithQuickSelectSort(int[] nums, int k) {
return quickSelect(nums, 0, nums.length - 1, nums.length - k);
}
/**
* 快速选择(单路)排序
* @param nums 数组
* @param start 起始元素位置
* @param end 结束元素位置
* @param k 查找位置
* @return
*/
private int quickSelect(int[] nums, int start, int end, int k) {
int partiton = randomPartiton(nums, start, end);
if (partiton == k) {
return nums[k];
} else {
return k < partiton ? quickSelect(nums, start, partiton - 1, k) : quickSelect(nums, partiton + 1, end, k);
}
}
/**
* 随机分区
* @param nums 数组
* @param start 起始元素位置
* @param end 结束元素位置
* @return
*/
private int randomPartiton(int[] nums, int start, int end) {
int random = start + new Random().nextInt(end - start + 1);
SortUtils.exchangeArrayEle(nums, start, random);
return partition(nums, start, end);
}
/**
* 双指针快排
* @param nums 数组
* @param start 起始元素位置
* @param end 结束元素位置
* @return
*/
private int partition(int[] nums, int start, int end) {
int left = start, right = end;
int povit = nums[start];
while (left < right) {
while (left < right && nums[right] >= povit) {
right--;
}
while (left < right && nums[left] <= povit) {
left++;
}
SortUtils.exchangeArrayEle(nums, left, right);
}
SortUtils.exchangeArrayEle(nums, left, start);
return left;
}
复杂度
* 时间 O(n)
* 空间 O(longn)