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:
Input: [3,2,1,5,6,4]
and k = 2
Output: 5
Example 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.
题目链接:https://leetcode.com/problems/kth-largest-element-in-an-array/
题目分析:求第k大
方法1:快速选择,基于快速排序的思想,时间复杂度O(n)
哨兵选左端点,31ms,时间击败32.5%
哨兵选中点,1ms,时间击败99%
class Solution {
public void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
public int quickSelect(int[] nums, int left, int right, int k) {
if (left > right) {
return 0;
}
int j = right, i = left;
swap(nums, left, (left + right) >> 1);
while (i < j) {
while (i < j && nums[j] >= nums[left]) {
j--;
}
while (i < j && nums[i] <= nums[left]) {
i++;
}
if (i < j) {
swap(nums, i, j);
}
}
swap(nums, i, left);
int cnt = i - left + 1;
if (cnt == k) {
return nums[i];
} else if (cnt < k) {
return quickSelect(nums, i + 1, right, k - cnt);
} else {
return quickSelect(nums, left, i - 1, k);
}
}
public int findKthLargest(int[] nums, int k) {
return quickSelect(nums, 0, nums.length - 1, nums.length - k + 1);
}
}
方法2:堆排,先构造大顶堆,堆顶和堆尾交换k-1次后的堆顶即为第k大
3ms,时间击败88%
class Solution {
public void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
public int heapSelect(int[] nums, int k) {
int n = nums.length;
for (int i = n / 2 - 1; i >= 0; i--) {
ajustHeap(nums, i, n);
}
int ansPos = n - 1;
for (; ansPos > 0 && k > 0; ansPos--, k--) {
swap(nums, 0, ansPos);
ajustHeap(nums, 0, ansPos);
}
return nums[0];
}
public void ajustHeap(int[] nums, int pos, int n) {
int tmp = nums[pos];
for (int i = pos << 1 | 1; i < n; i = i << 1 | 1) {
if (i + 1 < n && nums[i + 1] > nums[i]) {
i++;
}
if (nums[i] > tmp) {
nums[pos] = nums[i];
pos = i;
} else {
break;
}
}
nums[pos] = tmp;
}
public int findKthLargest(int[] nums, int k) {
return heapSelect(nums, k - 1);
}
}
方法3:二分,本题的输入均为32位整型,故可以直接对数字二分,先找到一个最小的x使得小于等于它的数字个数大于等于k,然后再找原数组中大于等于且与x最接近的数,即为答案,时间复杂度O(nlog2(常数)) => O(n),5ms,击败70%
class Solution {
public int n;
public int getLess(int x, int[] nums) {
int lessNum = 0;
for (int i = 0; i < n; i++) {
if (nums[i] <= x) {
lessNum++;
}
}
return lessNum;
}
public int getMid(int[] nums, int ma, int mi, int k) {
int l = mi, r = ma, mid = 0, ans = 0, lessNum = 0;
while (l <= r) {
mid = (l >> 1) + (r >> 1) + (l & r & 1);
lessNum = getLess(mid, nums);
if (lessNum <= k) {
l = mid + 1;
} else {
r = mid - 1;
ans = mid;
}
}
return ans;
}
public int findKthLargest(int[] nums, int k) {
n = nums.length;
int ma = nums[0], mi = nums[0];
for (int i = 0; i < n; i++) {
ma = Math.max(ma, nums[i]);
mi = Math.min(mi, nums[i]);
}
int tmid = getMid(nums, ma, mi, n - k);
int mid = nums[0], minDiff = ma - mi;
for (int i = 0; i < n; i++) {
if (nums[i] >= tmid && nums[i] - tmid < minDiff) {
minDiff = nums[i] - tmid;
mid = nums[i];
}
}
return mid;
}
}