数组中的第K个最大元素
给定整数数组 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
题解:
关于快排,我喜欢这个帖子https://blog.csdn.net/2302_78684687/article/details/138389058 很详细
因为我写快排的习惯不是很传统,所有每次遇到一些细节的问题都会卡一下,当然这里也可以用对堆,但是建堆的时间复杂度虽然是 O(n),取顶元素的时间复杂度却不是,每次删除顶端元素维护堆的时间成本是 logn,取 k 次就是 nlogn
go
func findKthLargest(nums []int, k int) int {
var quick func(l, r int) int
quick = func(l, r int) int {
if l == r {
return nums[l]
}
pivot := nums[l]
i, j := l, r
for i <= j {
for nums[i] > pivot {
i++
}
for nums[j] < pivot {
j--
}
if i <= j {
nums[i], nums[j] = nums[j], nums[i]
i++
j--
}
}
if k-1 <= j {
return quick(l, j)
}
if k-1 >= i {
return quick(i, r)
}
return nums[k-1]
}
return quick(0, len(nums)-1)
}
java
class Solution {
public int findKthLargest(int[] nums, int k) {
return quick(nums, k, 0, nums.length - 1);
}
// 这种写法,最后的 i , j 结局会交错,j 前, i 在后;
private int quick(int[] nums, int k, int l, int r) {
if (l >= r) {
return nums[k - 1];
}
int pivot = nums[(l + r) / 2];
int i = l;
int j = r;
while (i <= j) {
while (nums[i] > pivot) {
i++;
}
while (nums[j] < pivot) {
j--;
}
if (i <= j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
i++;
j--;
}
}
if (k - 1 <= j) {
return quick(nums, k, l, j);
}
if (k - 1 >= i) {
return quick(nums, k, i, r);
}
return nums[k - 1];
}
}
java
class Solution {
public int findKthLargest(int[] nums, int k) {
return quick(nums, k, 0, nums.length - 1);
}
// --- 这种写法最后 i 和 j 最终会指向一个元素
private int quick(int[] nums, int k, int l, int r) {
if (l >= r) {
return nums[k - 1];
}
int pivot = nums[l];
int i = l;
int j = r;
while (i < j) {
while (i < j && nums[j] <= pivot) {
j--;
}
nums[i] = nums[j];
while (i < j && nums[i] >= pivot) {
i++;
}
nums[j] = nums[i];
}
nums[i] = pivot;
if (i > k - 1) {
return quick(nums, k, l, i);
}
if (i < k - 1) {
return quick(nums, k, i + 1, r);
}
return nums[i];
}
}