难度:中等 相关标签:数组、分治、快速选择、排序、堆(优先队列) 给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。 请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1: 输入: [3,2,1,5,6,4], k = 2 输出: 5 示例2: 输入: [3,2,3,1,2,4,5,5,6], k = 4 输出: 4 提示: 1 <= k <= nums.length <= 105 -104<= nums[i] <= 104
我们知道,每次经过「划分」操作后,我们一定可以确定一个目标整数(每次默认最左边的)的最终位置 index,那么我们就在每次确定那个index后,就判断是否是符合要求的第K个最大整数的下标 p( = nums.lpength - k),
index = p ,直接返回那个目标整数就行
如果不是的话,
当index > p 时,则向 [ l, index - 1 ] 递归继续寻找
而当index < p 时,则向 [ index + 1, r ] 递归继续寻找
- class Solution {
-
- public int findKthLargest(int[] nums, int k) {
- int num = quickSelect( nums, 0, nums.length - 1, k );
- return num;
- }
-
- // 快速选择
- public int quickSelect( int[] nums, int l, int r, int k ) {
-
- // 获取这一趟快排后确认位置的 目标整数 的下标
- int index = quickSort( nums, l, r );
-
- // 如果这个确认的整数的下标刚好 == k,返回即可
- // 如果这个确认的整数的下标 > nums.length - k,则向 [ l, index - 1 ]递归继续寻找
- // 如果这个确认的整数的下标 < nums.length - k,则向 [ index + 1, r ]递归继续寻找
- if ( index == nums.length - k ) {
- return nums[ index ];
- } else {
- return index > nums.length - k ? quickSelect( nums, l, index - 1, k ) : quickSelect( nums, index + 1, r, k );
- }
- }
-
- // 快排的划分
- public int quickSort( int[] nums, int l, int r ) {
- int n = nums[ l ]; // 默认每一趟快排的目标整数位最左边的整数
- int index = l; // 记录目标整数的下标
- while ( l < r ) {
- while( l < r ) {
- if ( nums[ r ] < n ) {
- swap(nums, l, r);
- index = r;
- break;
- }
- r --;
- }
- while ( l < r ) {
- if ( nums[ l ] > n ) {
- swap(nums, l, r);
- index = l;
- break;
- }
- l++;
- }
- }
- return index;
- }
-
-
- // 定义交换方法
- public void swap( int[] nums, int i, int j ) {
- int temp = nums[ i ];
- nums[ i ] = nums[ j ];
- nums[ j ] = temp;
- }
-
-
- }
复杂度分析:时间复杂度:O(n),如上文所述,证明过程可以参考「《算法导论》9.2:期望为线性的选择算法」。
空间复杂度:O(\log n),递归使用栈空间的空间代价的期望为 O(logn)。