Leetcode-Algorithm-Divide and Conquer-215
-
题目:
-
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.
(找出无序数组中第k大的元素,也就是在有序时的第k大元素,而不是第k个不同元素。)
例子:
给定数组[3,2,1,5,6,4]以及k=2,那么结果为5。
题解:
方法1:
设数组长度为n,那么先排序,然后直接找到第n-k个元素就是第k大的元素。
代码:
int findKthLargest(vector<int>& nums, int k) {
if (nums.empty()) return -1;
sort(nums.begin(), nums.end());
return nums[nums.size()-k];
}
分析:
算法的时间复杂度其实就是排序所需要的时间复杂度,而排序的平均时间复杂度为
O(nlogn)
,因此,该方法的时间复杂度也是
O(nlogn)
。
方法2:(分治法)
设数组大小为n,那么找第k大的元素其实也就是找数组排序后位于n-k上的元素。因此从快速排序算法我们可以知道如何直接定位一个排序后元素的位置,通过快排中叫partition的那一步。当定位到一个元素时,如果它的位置pos在n-k的左边,那么我们就对pos往右的所有元素继续做partition操作;如果pos在n-k的右边,那么对pos往左的所有元素继续做partition操作;如果pos等于n-k,那么,这个元素就是我们想要的第k大元素。
代码:
int findKthLargest(vector<int>& nums, int k) {
if (nums.empty()) return -1;
return findKthLargestHelp(nums, 0, nums.size()-1, nums.size()-k);
}
int findKthLargestHelp(vector<int>& nums, int left, int right, int pos) {
if (left == right) return nums[left];
int ref = nums[left];
int i = left, j = right;
while (i < j) {
while (nums[j] > ref && j > i) j--;
if (i == j) break;
nums[i] = nums[j];
++i;
while (nums[i] < ref && i < j) ++i;
if (i == j) break;
nums[j] = nums[i];
--j;
}
nums[i] = ref;
if (i == pos)
return nums[i];
else if (i < pos)
left = i + 1;
else
right = i-1;
return findKthLargestHelp(nums, left, right, pos);
}
分析:
在平均情况下,一次partition都能将输入规模减少到其原来的一半,而我们只需要对含有第k大元素的那一半再做partition,而在分割过程需要
O(n)
次操作,因此我们可以得到下面的递推公式:
T(n)=T(n/2)+O(n)
由大师定理我们可以知道,该方法的时间复杂度为
O(n)