Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.
Example 1:
1 2
| Input: [3,2,1,5,6,4] and k = 2 Output: 5
|
Example 2:
1 2
| Input: [3,2,3,1,2,4,5,5,6] and k = 4 Output: 4
|
Note:
You may assume k is always valid, 1 ≤ k ≤ array’s length.
1 优先队列
维护一个k个元素组成的优先队列(小根堆), 如果遍历的元素i比优先队列里最小的元素大, 就poll掉最小的元素, 再把i加入到队列中.
最后, 优先队列中最小的元素即为第k大的元素.
复杂度 O(n * logk)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class Solution { public int findKthLargest(int[] nums, int k) { PriorityQueue<Integer> pq = new PriorityQueue<>(); for(int i : nums) { if(pq.size() < k) { pq.offer(i); } else { int tmp = pq.peek(); if(i > tmp) { pq.poll(); pq.offer(i); } } } return pq.peek(); } }
|
2 快速排序的思想
利用快速排序的思想, 随机选取一个哨兵sentinel = nums[begin]
然后将其partition两部分, 比sentinel小的在数组左边, 比sentinel大的在数组右边.
这样, 我们就能求出sentinel在数组中的排名是第end - j + 1
大的元素了. j为sentinel经过partition后最终的位置
如果k == sentinel_rank, 那么直接返回sentinel即可.
如果k > sentinel_rank, 那么说明第k大的数在sentinel左边的子数组中, 从nums[begin], 到nums[j - 1]中寻找第k - j大的元素即可
如果k < sentinel_rank, 那么说明第k大的数在sentinel右边的子数组中, 从nums[j+1]到nums[end]中寻找第k大的数即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| class Solution { public int findKthLargest(int[] nums, int k) { return kth(nums, 0, nums.length - 1, k); } private int kth(int[] nums, int begin, int end, int k) { int sentinel = nums[begin]; int i = begin; int j = end; while(true) { while(i < end && nums[i] <= sentinel) ++i; while(j > begin && nums[j] >= sentinel) --j; if(i >= j) { int tmp = nums[j]; nums[j] = nums[begin]; nums[begin] = tmp; break; } int tmp = nums[j]; nums[j] = nums[i]; nums[i] = tmp; } int sentinel_rank = end - j + 1; if(sentinel_rank == k) { return sentinel; } else if(sentinel_rank < k) { return kth(nums, begin, j - 1, k - sentinel_rank); } else { return kth(nums, j + 1, end, k); } } }
|