原题
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.
Example 1:
Input: [3,2,1,5,6,4] and k = 2
Output: 5
Example 2:
Input: [3,2,3,1,2,4,5,5,6] and k = 4
Output: 4
Note:
You may assume k is always valid, 1 ≤ k ≤ array’s length.
翻译
在一个未排序的数组中找到第k大的元素. 注意是排好序的第k大元素, 不是第k个不同的元素.
例 1:
输入: [3,2,1,5,6,4] and k = 2
输出: 5
例 2:
输入: [3,2,3,1,2,4,5,5,6] and k = 4
输出: 4
注意:
你可以假设k始终有效, 1 ≤ k ≤ 数组长度.
程序
快速选择 不清晰思路
class Solution {
public:
void swap(int& a,int& b)
{
int c = a;
a = b;
b = c;
}
void quickSort(vector<int>& nums,int left,int right)
{
//递归重要的返回条件
if (left > right||right<=0||left>=nums.size()-1)return;
int start = left;
int end = right;
int pivot = nums[right];
while (left != right)
{
if (nums[left] > pivot)
{
if (nums[right] < pivot)
swap(nums[left], nums[right]);
else
--right;
}
else
++left;
}
swap(nums[right],nums[end]);
//要习惯递归的思维
//这里不能直接写成从零开始,因为每次递归都不一样
quickSort(nums, start, right-1);
//这里不能直接写成从末尾开始,因为每次递归都不一样
quickSort(nums, left+1, end);
}
int findKthLargest(vector<int>& nums, int k) {
quickSort(nums,0,nums.size()-1);
return nums[nums.size()-k];
}
};
使用堆的思路
C++最小堆思路
int findKthLargest(vector<int>& nums, int k) {
// 最小堆
priority_queue< int, vector<int>, greater<int> > pq;
// add first k elements to heap, since min heap, min element will be at top
for (int i = 0; i < k; ++i) {
pq.push(nums[i]);
}
// for rest of elements...
// ... if it is greater than heap's top...
// ... pop from heap and push num to heap
// thereby maintaining heap size to be (k)
// one by one, all numbers in heap become the (k) largest numbers in array
for (int i = k; i < nums.size(); ++i) {
if (nums[i] > pq.top()) {
pq.pop();
pq.push(nums[i]);
}
}
// at the end, the number at top will be less than all numbers in heap
// that is, it will be kth largest
return pq.top();
}
C 最大堆思路
//传入 数组与数组长度与当前节点与左节点与右节点
//返回 在当前节点与其子节点中返回最大的一个节点下标
int max(int *a, int n, int i, int j, int k) {
int m = i;
//j<n 是判断子节点是否存在
if (j < n && a[j] > a[m]) {
m = j;
}
if (k < n && a[k] > a[m]) {
m = k;
}
return m;
}
//删除根节点
//传入 数组与数组长度与当前节点下标
void downheap(int *a, int n, int i) {
while (1) {
//从零开始不太好理解
//2*i+1是左节点
//2*i+2是右节点
int j = max(a, n, i, 2 * i + 1, 2 * i + 2);
//如果当前节点最大就没有 替换的必要了
if (j == i) {
break;
}
//将最大的子节点与当前节点进行替换
int t = a[i];
a[i] = a[j];
a[j] = t;
//将替换后的节点下标赋给i以便下次循环
i = j;
}
}
//堆排序
//传入 数组与数组长度
void heapsort(int *a, int n) {
int i;
//i从最后一个节点的父节点开始
//因为数组从零开始所以-2
//这一个for循环只是处理完全二叉树变成大顶堆
for (i = (n - 2) / 2; i >= 0; i--)
{
//删除根节点
downheap(a, n, i);
}
for (int i = 0; i < n; i++)
{
cout << a[i] ;
}
cout << endl;
//将最大值归位 即放在数组最后
for (i = 0; i < n; i++)
{
int t = a[n - i - 1];
a[n - i - 1] = a[0];
a[0] = t;
for (int i = 0; i < n; i++)
{
cout << a[i];
}
cout << endl;
//每次数组长度都减i 代表数组后面已经排好了
downheap(a, n - i - 1, 0);
}
for (int i = 0; i < n; i++)
{
cout << a[i] ;
}
cout << endl;
}
//小顶堆
int findKthLargest(int* nums, int numsSize, int k) {
//如果数组为空 k大于数组长度 返回
if (numsSize == 0) return 0;
if (numsSize == 1) return nums[0];
//进行堆排序
heapsort(nums, numsSize);
//取第k大的数
return nums[numsSize - k];
}
总结
-
swap是c++标准库函数
-
什么是down-heap?
对于最大堆,删除根节点就是删除最大值;
对于最小堆,是删除最小值。
然后,把堆存储的最后那个节点移到填在根节点处。
再从上而下调整父节点与它的子节点:
对于最大堆,父节点如果小于具有最大值的子节点,则交换二者。
这一操作称作down-heap或bubble-down, percolate-down, sift-down, trickle down, heapify-down, cascade-down,extract-min/max等。 -
快速选择与快速排序的异同
通过快速选择可以得到一组无序数字的第k大,原理基于快速排序,每次以某个数字为中点分成的左右两部分(程序中为了方便通常取最后一位,为了提高效率也可同时考虑开头中间结尾),左边都小于等于分割数,而右边都大于等于分割数 -
快速选择的平均时间复杂度是O(n),快速排序的平均时间复杂度是O(nlog(n))
-
快速排序(Quicksort),又称划分交换排序(partition-exchange sort)