題目描述:
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.
For example, Given [3,2,1,5,6,4] and k = 2, return 5.
解法一:
使用C++中提供的函數nth_element,直接找出所求元素,時間複雜度爲O(n)。最後用時很短,僅需9ms。
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
nth_element(nums.begin(), nums.end() - k, nums.end());
return nums[nums.size() - k];
}
};
解法二(使用分治算法):
根據書上的隨機分治算法,首先從數組中隨機選取一個元素v,重新安排數組,把比v大的元素放到數組左邊,比v小的數放在數組右邊,v的存儲位置m就說明v是數組中第m+1大的元素。如果m+1=k,說明v剛好是我們要找的元素;如果m+1< k,說明要找的元素在數組的右半段;反之,要找的元素在數組的左半段。算法如下圖所示,圖中
算法中還有一點需要考慮:選擇v後,如何將數組重排?實際上,可以先把目標元素存到數組末尾,然後遍歷數組,同時維護一個storeidx(初值爲0),如果遇到比目標元素大的元素,則與storeidx所代表的元素進行交換,然後將storeidx的值增加1,遍歷完成後storeidx的值就應該是目標元素最後需要存放的數組下標。這樣的話這一部分的空間複雜度僅爲O(1)。
整體代碼如下:
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
return selection(nums,0,nums.size() - 1,k);
}
int selection(vector<int>& nums, int left, int right, int k){
int random, storeidx, nums_rand;
int length = right - left + 1;
// pick a random element in array
srand(time(NULL));
random = rand() % length + left;
nums_rand = nums[random];
// put the elements larger than nums_rand to left, others to right
swap(nums[random],nums[right]);
storeidx = left;
for(int i = left;i < right;i++){
if(nums[i] > nums_rand){
swap(nums[storeidx], nums[i]);
storeidx++;
}
}
swap(nums[storeidx], nums[right]);
// find the kth largest number
if((storeidx - left + 1) == k) return nums_rand;
else if((storeidx - left + 1) > k) return selection(nums,left,storeidx - 1,k);
else return selection(nums, storeidx + 1, right, k - (storeidx - left + 1));
}
void swap(int &a,int &b){
int temp = a;
a = b;
b = temp;
}
};
該算法的思路其實和快排一致,運行速度也很快,最後運行時間爲9ms。