每日一题,防止痴呆 = =
一、题目大意
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/kth-largest-element-in-an-array
二、题目思路以及AC代码
思路一:快速排序
首先的第一个思路就是直接全部排序,然后返回下标为 size - k 的元素即可,这样的时间复杂度是O(NlogN),空间复杂度为O(1).
思路二:快速选择
另一个思路就是在快速排序的基础上去修改,从而得到快速选择算法,其思想是这样的。在快速排序的过程中,我们每次需要选择一个基准元素,然后确定这个基准元素的位置,使得其左边的元素都小于等于它,它右边的元素都大于等于它,然后再对两侧的子数组进行递归排序。
因为这里我们只需要找到排序后数组第 size - k 位置处的元素,所以我们大可不必要对所有数都进行排序,因为我们在第一次选择一个基准元素找到其位置后,可以判断我们要找的元素在其左侧还是右侧,假设在其右侧,那么我们只需要对右侧的数组进行排序就可以了,不需要对左侧的数组也进行排序,这样就可以优化时间复杂度。
但是我们知道如果基准元素选择的不好,遇到最差的情况时间复杂度也会达到O(N2)的,所以这里采用每次随机选择基准元素的方法,从而使期望的时间复杂度为O(N)。
AC代码
快速排序:
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
int n_size = nums.size();
sort(nums.begin(), nums.end());
return nums[n_size - k];
}
};
快速选择:
class Solution {
public:
int quick_selection(vector<int>& nums, int l, int r, int index) {
int q = random_partition(nums, l, r);
if (q == index) return nums[q];
else if (q < index) return quick_selection(nums, q + 1, r, index);
else return quick_selection(nums, l, q - 1, index);
}
int random_partition(vector<int>& nums, int l, int r) {
int i = rand() % (r - l + 1) + l;
swap(nums[i], nums[r]);
return partition(nums, l, r);
}
int partition(vector<int>& nums, int l, int r) {
int target = nums[r];
int i = l;
for (int j=l;j<r;j++) {
if (nums[j] <= target) {
swap(nums[i++], nums[j]);
}
}
swap(nums[i], nums[r]);
return i;
}
int findKthLargest(vector<int>& nums, int k) {
srand(time(0));
return quick_selection(nums, 0, nums.size() - 1, nums.size() - k);
}
};
如果有问题,欢迎大家指正!!!