一、题目
给定整数数组 nums
和整数 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
二、补充知识:
快排的基本思想:
partition 分区函数会任意选择一个元素(该解法中选择最后一个元素arr[len-1])作为 mid(分区点),将数组中小于 mid 的点都放置到其左边,将大于mid的点都放置在其右边,最终 partition 函数返回 mid 的下标 i
经过这一步骤后,数组将分成3部分
1、arr[0] ~ arr[i-1] 都是不大于 mid 的元素
2、arr[i+1] ~ arr[len-1] 都是不小于 mid 的元素
3、arr[i] 是 pivot 元素
quick_sort(int[] arr, int low, int high) {
if (low >= high) return;
int i = partition(arr, low, high);
quick_sort(arr, low, i-1);
quick_sort(arr, i+1, high);
}
三、解题思路
使用快速排序思想,由于官方题解有点晦涩难懂,生成的partition随机位置难懂,因此结合了快速排序思想。给出了如下思路:
1、当partition的位置正好是第K大元素的位置,则直接返回mid。
2、当partition的位置<第K大元素的位置,则low=mid+1,即该元素的位置应该在mid的右边。
3、当partition的位置>第K大元素的位置,则high=mid-1,即该元素的位置应该在mid的左边。
三、代码
class Solution {
public int findKthLargest(int[] nums, int k) {
int len=nums.length;
int kth=len-k;
int low=0;
int high=len-1;
while(low<=high) {
int mid=partition(nums,low,high);//mid存放每次partition的位置
if(mid==kth) {//当partition的位置正好是第K大元素的位置,则直接返回mid
return nums[mid];
}else if(mid<kth) {//当partition的位置<第K大元素的位置,则low=mid+1,即该元素的位置应该在mid的右边
low=mid+1;
}else {//当partition的位置>第K大元素的位置,则high=mid-1,即该元素的位置应该在mid的左边
high=mid-1;
}
}
return nums[kth];
}
public int partition(int[] nums,int low,int high) {
int i=low;//i用来记录当前<privor尾节点的位置
int privor=nums[high];//默认nums[high]为privor
//快排思想,所有小于privor的数移到privor的左边,大于privor的数移动到它的右边
for(int j=low;j<high;j++) {
if(nums[j]<privor) {
swap(nums, i, j);
i++;
}
}
//最后i指向的是privor的最终位置
swap(nums,i,high);
return i;
}
//交换两个数
public void swap(int[] nums,int i,int j) {
int temp=nums[i];
nums[i]=nums[j];
nums[j]=temp;
}
}