每日一題,防止癡呆 = =
一、題目大意
在未排序的數組中找到第 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);
}
};
如果有問題,歡迎大家指正!!!