用于求解 Kth Element 问题,使用快速排序的 partition() 进行实现。
需要先打乱数组,否则最坏情况下时间复杂度为 O(N2)。
快速选择也可以求解 TopK Elements 问题,因为找到 Kth Element 之后,再遍历一次数组,所有小于等于 Kth Element 的元素都是 TopK Elements。
快速排序是原地排序,不需要辅助数组,但是递归调用需要辅助栈。
快速排序最好的情况下是每次都正好能将数组对半分,这样递归调用次数才是最少的。这种情况下比较次数为 CN=2CN/2+N,复杂度为 O(NlogN)。
最坏的情况下,第一次从最小的元素切分,第二次从第二小的元素切分,如此这般。因此最坏的情况下需要比较 N2/2。为了防止数组最开始就是有序的,在进行快速排序时需要随机打乱数组。
class Solution {
public int findKthLargest(int[] nums, int k) {
//打乱数组
//shuffle(nums);
//快速排序
/*
求第K大转化成求第n-k+1小,n=numbers.length
n=9,第三大k=3;第7小元素9-3+1
一轮快速排序返回j表示第j+1小的元素
如果返回的j==k刚好是第k个最小元素,退出
如果返回的j<k 比第k个元素小,返回第3个,但是要求第6个,则对第三个元素后面的元素进行排序
如果返回的j>k 比第k个元素大,返回第9个最小元素,但是要求第6个,则对第九个元素前面的元素进行排序
*/
/*
求第K大元素,n=numbers.length n-k表示第k大元素所在数组的索引
n=9,第三大k=3;索引是6
一轮快速排序返回j表示第j大元素的索引
如果返回的j==k刚好是第k个最大元素,退出
如果返回的j<k 比第n-k个索引小,则对第j个索引后面的元素进行排序
如果返回的j>k 比第n-k个索引大,则对第j个索引之前的元素进行排序
*/
int length=nums.length;
//此时的k由求第K大元素的索引值;刚好是快速排序返回的值
k=length-k;
int l=0;
int h=length-1;
while(l<h){
int jth_min= quickSort(nums,l,h);
if(jth_min==k){
break;
}else if(jth_min<k){
l=jth_min+1;
}else{
h=jth_min-1;
}
}
return nums[k];
}
//快速排序代码
public int quickSort(int[] nums,int l,int h){
int i=l;
int j=h;
//以最后一个元素作为参考,对数组进行快速排序
while(true){
while(nums[i]<=nums[h]&&i<h){i++;}//i=3
while(nums[j]>nums[h]&&j>l){j--;}//j=2
if(i>=j){
break;
}
swap(nums,i,j);
}
swap(nums,i,h);
return i;
}
public void swap(int[] nums,int l,int h){
int temp=nums[l];
nums[l]=nums[h];
nums[h]=temp;
}
}