题目
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
思路
快速选择,不管你是否有序,我只要把比我小的放在我的左边。然后不断切分区间
- 得到第一次 partition 的区间 left 和 right
- 计算目标下标(第 k 大的元素就是,从左边数第 len - k 个)
6个数中,找第2大的,即下标为4
6个数中,找第4大的,即下标为2 - 对目标进行 partition, 返回值已确定的下标
- 检查下标与目标下标的差距,重新界定 partition 区间
快速选择算法
// 快速选择
class Solution {
private static Random random = new Random(System.currentTimeMillis());
public int findKthLargest(int[] nums, int k) {
int left = 0;
int len = nums.length;
int right = len - 1;
int target = len - k;
while (true){
int index = partition(nums, left, right);
if (index == target){
return nums[index];
}
else if(index > target){
right = index - 1;
}
else if(index < target){
left = index + 1;
}
}
}
public int partition(int[] nums, int left, int right){
if(right > left){
int randomIndex = left + 1 + random.nextInt(right - left);
swap(nums, left, randomIndex);
}
int pivot = nums[left];
int j = left;
// 这里的 i 从left+1开始
for(int i=left+1; i<=right; i++){
// 小于我的数字都放在左边
if(nums[i] <= pivot){
j ++;
swap(nums, j, i);
}
}
// 之前大于pivot的值,都会被安放在left的右边,此时将小于pivot的最大达标j与left交换
swap(nums, left, j);
// 那么j以前的数字都会小于nums[j],但是不一定都有序。。。
return j;
}
public void swap(int[] nums, int index1, int index2){
int temp = nums[index1];
nums[index1] = nums[index2];
nums[index2] = temp;
}
}