题目描述
在未排序的数组中找到第 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
题解
1.最容易想到的就是先排序,然后获取下标为length - k 的元素
2.使用堆排序的思想,建立大顶堆,将所有数组中的元素加入堆中,并保持堆的大小小于等于 k。这样,堆中就保留了前 k 个最大的元素。这样,堆顶的元素就是正确答案。
class Solution {
public int findKthLargest(int[] nums, int k) {
// init heap 'the smallest element first'
PriorityQueue<Integer> heap =
new PriorityQueue<Integer>((n1, n2) -> n1 - n2);
// keep k largest elements in the heap
for (int n: nums) {
heap.add(n);
if (heap.size() > k)
heap.poll();
}
// output
return heap.poll();
}
}
3.使用快排的思想,首先随机选择一个枢轴。
然后使用划分算法将枢轴放在数组中的合适位置 pos。将小于枢轴的元素移到左边,大于等于枢轴的元素移到右边。
比较 pos 和 N - k 以决定在哪边继续递归处理。这样我们只用处理单边的序列,节省时间。
时间复杂度 : 平均情况 O(N),最坏情况 O(N 2 )。
空间复杂度 : O(1)。
class Solution {
public void swap(int[] nums, int a, int b) {
int tmp = nums[a];
nums[a] = nums[b];
nums[b] = tmp;
}
public int partition(int[] nums, int left, int right, int pivot_index) {
int pivot = nums[pivot_index];
// 1.把轴移动到末尾
swap(nums,pivot_index, right);
int store_index = left;
// 2.将所有小于基准的移到左边
for (int i = left; i <= right; i++) {
if (nums[i] < pivot) {
swap(nums,store_index, i);
store_index++;
}
}
// 3.把基准归位
swap(nums,store_index, right);
return store_index;
}
public int quickselect(int[] nums, int left, int right, int k_smallest) {
if (left == right)
return nums[left];
//生成随机值作为下标
Random random_num = new Random();
int pivot_index = left + random_num.nextInt(right - left);
pivot_index = partition(nums,left, right, pivot_index);
//判断基准和所求位置的关系,相等则返回
if (k_smallest == pivot_index)
return nums[k_smallest];
//小于则说明在左边,对左边的序列进行排序寻找
else if (k_smallest < pivot_index)
return quickselect(nums,left, pivot_index - 1, k_smallest);
//大于则在右边
return quickselect(nums,pivot_index + 1, right, k_smallest);
}
public int findKthLargest(int[] nums, int k) {
int size = nums.length;
return quickselect(nums,0, size - 1, size - k);
}
}