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.
Note: You may assume k is always valid, 1 ≤ k ≤ array’s length.
题目:从一个无序的数组里面找出第K大的元素。当K=1,时,第K大的元素就是数组中最大的元素;K=2时,就是找出数组中第二大的元素。
我想到了三种方法:直接排序,最大堆和快速排序(分治)。
最简单的方法就是先对数组排序,然后直接返回第n-k个元素。这种方法的时间复杂度为O(nlogn)(排序),空间复杂度为O(1) (通过下标索引元素)。
// sortint findKthLargest(vector<int>& nums, int k) { sort(nums.begin(), nums.end()); return nums[nums.size()-k];}Rumtime: 9ms
第一种方法对所有元素排序后取出第K大的元素,但是其实没有必要对所有元素排序,因为我们只关心第K大的元素,因此可以使用最大堆:对所有元素建立最大堆,保证堆顶的元素最大,再删除k-1个元素后,此时堆顶的元素就是第K大的元素了。这种方法的时间复杂度为O(n log n), 空间复杂度为O(n).
// max heap: make a max heap with all elements, then pop k-1 elementsint findKthLargest(vector<int>& nums, int k) { PRiority_queue<int> max_heap (nums.begin(), nums.end()); for (int i = 0; i < k-1; ++i) { max_heap.pop(); } return max_heap.top();}Runtime: 9 ms
使用最大堆需要对所有元素排序,这样花费了时间和空间,因此可以转换一下思想,使用最小堆:先对数组中的前k个元素建立最小堆,然后依次遍历剩下的元素,当元素大于堆顶的元素时,将堆顶元素弹出,插入这个新的元素。这样到最后的最小堆中的就是k个最大的元素,堆顶的元素就是第k大的元素。这样可以将时间复杂度将为O(nlogk), 空间复杂度降为O(k)
int findKthLargest(vector<int>& nums, int k) { priority_queue<int, vector<int>, greater<int> > min_heap (nums.begin(), nums.begin()+k); for (int i = k; i < nums.size(); ++i) { if (nums[i] > min_heap.top()) { min_heap.pop(); min_heap.push(nums[i]); } } return min_heap.top();}但是这道题目的tag标为divide-and-conquer,就说明可以使用分治的思想来实现。寻找第k大的元素,其实就是寻找第n-k+1小的元素,那么我们可以采用快速选择(Quick Select)的方法:随机寻找一个pivot,将小于pivot的元素放在左边,大于pivot的元素放在右边。partion后,pivot左边的元素都小于pivot,右边的元素都大于pivot。那么假设pivot对应的下标为i,如果i==n-k+1,那么pivot就是要找的第K大的元素;如果i < n-k+1,说明需要找的元素在pivot的右边。这种方法的时间复杂度为O(nlogn)。
// divide-and-conquer: quick-sortint findKthLargest(vector<int>& nums, int k) { int index = quickSelec(nums, 0, nums.size()-1, nums.size()-k+1); return nums[index];}int quickSelec(vector<int>& a, int low, int high, int k) { int l = low, h = high, pivot = a[high]; while(l < h) { if (a[l++] > pivot) swap(a[--l], a[--h]); } swap(a[l], a[high]); int cnt_small = l - low + 1; // count nums that are <= pivot // pivot is the target if (cnt_small == k) return l; // pivot is too big, so target in left else if (cnt_small > k) return quickSelec(a, low, l-1, k); // pivot is too small, so target in right else return quickSelec(a, l+1, high, k-cnt_small);}新闻热点
疑难解答