215. 数组中的第K个最大元素
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2 输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4 输出: 4
说明:
你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。
方法一:先进行一次快速排序,在排好序的数组中获得第k-1个元素, 时间复杂度为O(nlogn).
class Solution {
public int findKthLargest(int[] nums, int k) {
quickSort(nums, 0, nums.length-1);
return nums[k-1];
}
//快排
public void quickSort(int[] a, int start, int end){
//递归入口
if (start>=end){
return;
}
int i=start;
int j=end;
int key=a[start];
//进行一次快排
while(i<j){
while(a[j]<=key && i<j){
j--;
}
while(a[i]>=key && i<j){
i++;
}
if(i<j){
int temp=a[j];
a[j]=a[i];
a[i]=temp;
}
}
int temp = a[i];
a[i]=key;
a[start]=temp;
quickSort(a, start, i-1);
quickSort(a, i+1, end);
}
}
方法二:经典思路,利用快排的思想实现,通过positition的位置进行判断,降低时间复杂度,为O(n).
class Solution {
public int findKthLargest(int[] nums, int k) {
return findKth(nums, 0, nums.length-1, k-1);
}
private int positition(int[] arr, int l, int r){
//随机选取标定点
int index = (int)(Math.random()*(r-l+1)+l);
int temp = arr[index];
arr[index] = arr[l];
arr[l] = temp;
int v = arr[l];
//双路快排
int i=l+1, j=r;
while (true){ //while判断为真, 可以保证即使只有两个元素时,即i=l+1=j 时,也可以进入循环
while (i<=r && arr[i]>v){ //i停下的位置一定是小于或等于v的位置
i++;
}
while (j>=l+1 && arr[j]<v){ //j停下的位置一定是大于或等于v的位置
j--;
}
if(i>j){ //只能取大于
break;
}
int temp0 = arr[i];
arr[i]=arr[j];
arr[j] = temp0;
i++;
j--;
}
int temp1 = arr[l];
arr[l] = arr[j];
arr[j]= temp1; //j落在最后一个大于等于v的位置, i落在第一个小于等于v的位置,最终i不等于j, 而l处需要一个大于v的值,所以只能和 j 处的交换
return j;
}
private int findKth(int[] arr, int l, int r, int k){
if(l==r){
return arr[l];
}
int p = positition(arr, l, r);
if(k==p){
return arr[p];
}else if(k<p){
return findKth(arr, l, p-1, k);
}else{
return findKth(arr, p+1, r, k);
}
}
}