题意:求数组中第k大的元素;这里只分析时间复杂度为nlogn的方法
#include<iostream>
#include<vector>
#include<queue>
#define Error -1
#include<cmath>
using namespace std;
//方法一:大顶堆的底层实现,分三部分:层序遍历生成完全二叉树、将完全二叉树修改成小顶堆、将剩下的n-k个元素遍历对小顶堆做修改
class Solution {
public:
class ComBiTree
{
public:
int value;
ComBiTree* left;
ComBiTree* right;
ComBiTree(int x) :value(x), left(nullptr), right(nullptr) {};
ComBiTree() :value(0), left(nullptr), right(nullptr) {};
};
int findKthLargest(vector<int>& nums, int k) {
if (k > nums.size()) return Error;
//创建k个节点的完全二叉树
queue<ComBiTree*>que;
ComBiTree* Head = new ComBiTree(nums[0]);
que.push(Head);
for (int i = 1; i < k; i++)
{
ComBiTree* TreeNode = new ComBiTree(nums[i]);
if (!que.empty())
{
if (!que.front()->left) que.front()->left = TreeNode;
else
que.front()->right = TreeNode;
if (que.front()->left && que.front()->right)
que.pop();
}
que.push(TreeNode);
}
//while (!que.empty())
//{
// que.pop();
//}
将完全二叉树改成小顶堆完全二叉树
//for (int i = 0; i < (k - 1) / 2; i++)
//{
// recursion(Head);
//}
//自己的这种方法,似乎只需要循环深度减1次,这一点和很多博客上的方法不同,因为我考虑了树的所有分支
//将完全二叉树改成小顶堆完全二叉树
for (int i = 0; i < log(k + 1) / log(2) - 1; i++)
{
recursion(Head);
}
//将后面n-k个元素依次遍历,修改现有的小顶堆
for (int i = k; i < nums.size(); i++)
{
if (nums[i] <= Head->value)
continue;
else
ModComBiTree(Head, nums[i]);
}
return Head->value;
}
void ModComBiTree(ComBiTree*& TreeNode, int k) {
if (TreeNode->left && TreeNode->right)
{
if ((k <= TreeNode->left->value) && (k <= TreeNode->right->value))
TreeNode->value = k;
else
{
if (TreeNode->left->value < TreeNode->right->value)
{
TreeNode->value = TreeNode->left->value;
ModComBiTree(TreeNode->left, k);
}
else
{
TreeNode->value = TreeNode->right->value;
ModComBiTree(TreeNode->right, k);
}
}
}
else if (TreeNode->left)
{
if (TreeNode->left->value < k)
{
TreeNode->value = TreeNode->left->value;
ModComBiTree(TreeNode->left, k);
}
else
TreeNode->value = k;
}
else
TreeNode->value = k;
}
void recursion(ComBiTree*& Treenode)
{
if (!Treenode) return;
if (Treenode->left) {
recursion(Treenode->left);
if (Treenode->right)
recursion(Treenode->right);
int temp;
if (Treenode->right)
{
if (Treenode->left->value < Treenode->right->value)
{
if (Treenode->left->value < Treenode->value)
{
temp = Treenode->left->value;
Treenode->left->value = Treenode->value;
Treenode->value = temp;
}
}
else
{
if (Treenode->right->value < Treenode->value)
{
temp = Treenode->right->value;
Treenode->right->value = Treenode->value;
Treenode->value = temp;
}
}
}
else
{
if (Treenode->left->value < Treenode->value)
{
temp = Treenode->left->value;
Treenode->left->value = Treenode->value;
Treenode->value = temp;
}
}
return;
}
else
return;
}
};
//方法二:网友快速排序法,这种方法,在leetcode上运行时间最短
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
int n = nums.size();
int left = 0;
int right = n - 1;
while (left <= right) {
int pivotIdx = left + rand() % (right - left + 1);
int finalIdx = partition(nums, left, right, pivotIdx);
if (finalIdx == n - k) {
return nums[finalIdx];
}
else if (finalIdx > n - k) {
right = finalIdx - 1;
}
else {
left = finalIdx + 1;
}
}
return -1;
}
int partition(vector<int>& nums, int left, int right, int pivotIdx) {
int pivot = nums[pivotIdx];
int i = left;
swap(nums[right], nums[pivotIdx]); //move the pivot to the end
for (int j = left; j < right; j++) {
if (nums[j] < pivot) {
swap(nums[j], nums[i]);
i++;
}
}
swap(nums[i], nums[right]);
return i;
}
};
//方法三:网友法,直接用STL库priority_queue
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
priority_queue<int, vector<int>, greater<int>> PQ;
for (int i = 0; i < nums.size(); i++)
{
PQ.push(nums[i]);
if (PQ.size() > k) PQ.pop();
}
return PQ.top();
}
};