Leetcode学习之栈、队列、堆(3)

开宗明义:本系列基于小象学院林沐老师课程《面试算法 LeetCode 刷题班》,刷题小白,旨在理解和交流,重在记录,望各位大牛指点!


Leetcode学习之栈、队列、堆(3)


文章目录

    • 1、STL优先级队列(二叉堆)
    • 2、求数组中第K大的数(Top K) Leetcode 215.
    • 3、寻找中位数 Leetcode 295.


1、STL优先级队列(二叉堆)

:通常可以被看做一棵树,它满足下列性质:

  1. 堆中任意节点的值总是不大于(不小于)其子节点的值
  2. 堆总是一棵完全树

二叉堆:二叉堆是完全二元树或者是近似完全二元树,它分为两种:最大堆最小堆
最大堆:父结点的键值总是大于或等于任何一个子节点的键值;
最小堆:父结点的键值总是小于或等于任何一个子节点的键值。

Leetcode学习之栈、队列、堆(3)_第1张图片
二叉堆,也叫优先级队列,STL包含到 # i n c l u d e < q u e u e > \#include <queue> #include<queue>中。
测试代码

#include 
#include 
using namespace std;

//优先输出大数据
//priority_queue
//Type为数据类型, Container为保存数据的容器,Functional为元素比较方式。
//如果不写后两个参数,那么容器默认用的是vector,比较方式默认用operator<,也就是优先队列是大顶堆,队头元素最大。

int main() {
	priority_queue<int> big_heap;//默认构造的就为最大堆、

	//priority_queue, isgreater> small_heap;//最小堆构造方法
	priority_queue<int, std::vector<int>, std::less<int>> big_heap2;//最大堆构造方法

	if (big_heap.empty()) {
		printf("big_heap is empty!\n");
	}

	int test[] = { 6,10,1,7,99,4,33 };
	for (int i = 0; i < 7; i++) {
		big_heap.push(test[i]);//把元素push进入最大堆
	}
	printf("big_heap.top=%d\n", big_heap.top());//打印这个优先级队列的第一个元素,普通的queue是33,但是最大堆应为99
	big_heap.push(1000);
	printf("big_heap.top=%d\n", big_heap.top());//这时候应该1000
	for (int i = 0; i < 3; i++) {
		big_heap.pop();
	}
	printf("big_heap.top=%d\n", big_heap.top());//这时候应该10
	printf("big_heap.size=%d", big_heap.size());
	system("pause");
	return 0;
}

效果图
Leetcode学习之栈、队列、堆(3)_第2张图片


2、求数组中第K大的数(Top K) Leetcode 215.

题目来源 L e e t c o d e   215.   K t h   L a r g e s t   E l e m e n t   i n   a n   A r r a y Leetcode \ 215.\ Kth \ Largest \ Element \ in \ an \ Array Leetcode 215. Kth Largest Element in an Array
题目描述已知一个未排序的数组,求这个数组中第K大的数字,如,array=[3,2,1,5,6,4],k=2,return 5
思路维护一个K大小的最小堆,堆中元素个数小于K时,新元素直接进入堆中;否则,当堆顶的元素小于新元素时,弹出堆顶,将新元素加入堆,注意啊:加入堆的话,会调整堆,因为这个堆只有k大小,进来一个就会出去一个。这样做的理由:使用的堆为最小堆,堆顶是堆中最小的元素,新元素都会保证比堆顶小,因为新元素比堆顶大的话,会进入堆,调整堆。所以堆中K个元素是已扫描的元素里最大的K个。堆顶即第K大的数。
设数组长度为 N N N,求第 K K K大的数,时间复杂度为: N ∗ l o g K N*logK NlogK
Leetcode学习之栈、队列、堆(3)_第3张图片
测试代码

#include 
#include 
using namespace std;

class Solution {
public:
	//这边是重载
	template <class _Tp>
	struct greater : public binary_function<_Tp, _Tp, bool>
	{
		bool operator()(const _Tp& __x, const _Tp& __y) const { return __x > __y; }
	};

	int findKthLargest(vector<int>& number, int k) {
		priority_queue<int, vector<int>, greater<int>> Q;
		for (int i = 0; i < number.size(); i++) {//遍历number数组
			if (Q.size()<k) {//如果堆中元素个数小于K,直接push进入堆
				Q.push(number[i]);
			}
			else if (number[i] > Q.top()) {//如果堆顶比新元素小,弹出堆顶
				Q.pop();
				Q.push(number[i]);//push进入,代替新元素
			}
		}
		return Q.top();//返回堆顶
	}
};

int main() {
	vector<int> nums;
	nums.push_back(3);
	nums.push_back(2);
	nums.push_back(1);
	nums.push_back(5);
	nums.push_back(6);
	nums.push_back(4);
	Solution solve;
	printf("%d\n", solve.findKthLargest(nums, 2));
	system("pause");
	return 0;
}

效果图
Leetcode学习之栈、队列、堆(3)_第4张图片


3、寻找中位数 Leetcode 295.

题目来源: L e e t c o d e   295.   F i n d   M e d i a n   f r o m   D a t a   S t r e a m Leetcode \ 295. \ Find \ Median \ from \ Data \ Stream Leetcode 295. Find Median from Data Stream
题目描述:设计一个数据结构,该数据结构动态维护一组数据,且支持如下操作
1、添加元素:void addNum(int num),将整型num添加至数据结构中
2、返回数据的中位数:double findMedian(),返回其维护的数据的中位数
其中,中位数的定义
1.若数据个数为奇数,中位数是该组数排序后中间的数。如[1,2,3]->2
2. 若数据个数为偶数,中位数是该组数排序后中间两个数字的平均值。如[1,2,3,4]->2.5
要求描述
Leetcode学习之栈、队列、堆(3)_第5张图片
思路Leetcode学习之栈、队列、堆(3)_第6张图片
复杂度太高->巧用堆的性质动态维护一个最大堆与最小堆,最大堆存储一半数据,最小堆存储一半的数据,维持的状态是:最大堆的堆顶比最小堆的堆顶小
有三种情形:①偶数,最大堆与最小堆各一半;
②奇数,最大堆比最小堆多一个元素;
③奇数,最大堆比最小堆少一个元素;
Leetcode学习之栈、队列、堆(3)_第7张图片

测试代码:

#include 
#include 

using namespace std;

class Solution {
public:
	//这边是重载
	template <class _Tp>
	struct greater : public binary_function<_Tp, _Tp, bool>
	{
		bool operator()(const _Tp& __x, const _Tp& __y) const { return __x > __y; }
	};

	priority_queue<int, std::vector<int>, greater<int>> small_queue;//最小堆构造方法
	priority_queue<int, std::vector<int>, std::less<int>> big_queue;//最大堆构造方法

	void addNum(int num) {
		if (big_queue.empty()) {  
			big_queue.push(num);
			return;
		}
		if (big_queue.size() == small_queue.size()) {
			if (num < big_queue.top()) {
				big_queue.push(num);
			}
			else
			{
				small_queue.push(num);
			}
		}
		else if(big_queue.size() > small_queue.size())
		{
			if (num >big_queue.top()) {
				small_queue.push(num);
			}
			else
			{
				small_queue.push(big_queue.top());
				big_queue.pop();
				big_queue.push(num);
			}
		}
		else if (big_queue.size() < small_queue.size()) {
			if (num < small_queue.top()) {
				big_queue.push(num);
			}
			else
			{
				big_queue.push(small_queue.top());
				small_queue.pop();
				small_queue.push(num);
			}
		}
	}

	double findMedian() {
		if (big_queue.size() == small_queue.size()) {
			return (big_queue.top() + small_queue.top()) / 2;
		}
		else if (big_queue.size() > small_queue.size()) {
			return big_queue.top();
		}
		return small_queue.top();
	}
};

int main() {
	Solution solve;
	int test[] = { 6,10,1,7,99,4,33 };
	for (int i = 0; i < 7; i++) {
		solve.addNum(test[i]);
		printf("%1f\n", solve.findMedian());
	}
	system("pause");
	return 0;
}

效果图
Leetcode学习之栈、队列、堆(3)_第8张图片

你可能感兴趣的:(Leetcode)