215.数组中的第k个最大元素
问题:给定整数数组 nums 和整数k ,请返回数组中第k 个最大的元素。
请注意,你需要找的是数组排序后的第k 个最大的元素,而不是第k 个不同的元素。
思路:
这是最容易想到的思路,首先将数组排序,然后取倒数第k个就是所求。注意Arrays.sort() 默认为自然排序,无法对基本数据类型的数据进行自定义排序,但是可以对其包装类Integer类型的数组自定义排序。
class Solution {
public int findKthLargest(int[] nums, int k) {
Arrays.sort(nums);
return nums[nums.length - k];
}
}
java的优先队列默认实现为小顶堆。将数组中的元素依次入队列,在此过程中,维护一个长度为k 的队列,当队列长度大于k 时,将堆顶元素(当前队列中最小的元素)出队,这样当整个数组遍历完之后,我们就留下了较大的k 个元素,即堆顶为第k 大元素。
class Solution {
public int findKthLargest(int[] nums, int k) {
Queue<Integer> priorityQueue = new PriorityQueue<>();
for(int num: nums){
priorityQueue.offer(num);
if(priorityQueue.size() > k){
priorityQueue.poll();
}
}
return priorityQueue.peek();
}
}
快速选择算法是快速排序算法的优化版本。
快速排序的逻辑是,若要对 nums[l..r] 进行排序,我们先找一个分界点 p ,通过交换元素使得 nums[l..r] 都小于等于 nums[p] ,且 nums[p+1..r] 都大于 nums[p] ,然后递归地去 nums[l..p-1] 和 nums[p+1..r] 中寻找新的分界点,最后整个数组就被排序了。
需要优化的点在这里:每一次快排之后,分界点p的位置会被确定,我们要求的是第k大元素,这个第k大元素在升序后的数组中的位置为nums.length - k 。既然我们知道了所求元素的位置,且每一次快排会确定分界点p的位置。那我们可以是用确定位置的分界点p和k作比较,若p < k ,则说明第k大元素肯定在区间[p+1, r] ,若p > k ,则说明第k大元素肯定在区间[l, p - 1] 。p == k ,则nums[p]即为所求。
class Solution {
public int findKthLargest(int[] nums, int k) {
int l = 0, r = nums.length - 1;
k = nums.length - k;
while(l <= r){
int p = partition(nums, l, r);
if(p < k){
l = p + 1;
} else if(p > k){
r = p - 1;
} else {
return nums[p];
}
}
return -1;
}
private int partition(int[] nums, int l, int r) {
if (l == r) {
return l;
}
int pivot = nums[l];
int i = l, j = r + 1;
while (true){
while (nums[++i] < pivot){
if (i == r) {
break;
}
}
while (nums[--j] > pivot){
if (j == l) {
break;
}
}
if(i >= j) {
break;
}
swap(nums, i, j);
}
swap(nums,j,l);
return j;
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
整理思路,记录博客,以便复习。若有误,望指正~
|