leetcode part2 栈和队列

/**
第二课   堆栈和队列

栈      后进先出的线性表
队列    先进先出的线性表

STL 中的栈
栈的5个基本操作
(1)S.top()    取出栈顶元素(但并不弹出)
(2)S.empty()  判断栈是否为空
(3)S.push(x)  将x压入栈中
(4)S.pop()    弹出栈顶元素
(5)S.size()   栈的存储元素个数

**/

#include<iostream>
#include<vector>
using namespace std;

#include<stdio.h>
#include<stack>

int main(){
    stack<int> s;
    if(s.size()==0){
        cout<<"s is empty! "<<endl;
    }
    s.push(5);
    s.push(6);
    s.push(10);

    cout<<"s.top= "<<s.top()<<endl;
    s.pop();
    s.pop();
    cout<<"s.top= "<<s.top()<<endl;
    cout<<"s.size= "<<s.size()<<endl;
    return 0;
}

/**
STL 中的队列
STL 中队列的6个基本操作
(1)Q.empty()  判断队列是否为空
(2)Q.front()  返回队列头部元素
(3)Q.back()   返回队列尾部元素
(4)Q.pop()    弹出队列头部元素
(5)Q.push(x)  将元素x添加到队列的尾部
(6)Q.size()   返回队列的存储元素个数
**/
using namespace std;
#include<iostream>
#include<stdio.h>
#include<queue>
#include<assert.h>
int main(){
    queue<int> Q;
    if(Q.empty()){
        cout<<"Q is empty "<<endl;
    }
    Q.push(5);
    Q.push(6);
    Q.push(10);
    assert(Q.front()==5);
    Q.pop();
    Q.pop();
    assert(Q.front()==10);
    Q.push(1);
    assert(Q.back()==1);
    assert(Q.size()==2);
    return 0;
}

/**
leetcode 225  用队列实现栈
用两个队列实现一个栈
栈可以使用数组和top指针实现

如果都用vector实现栈和队列
栈的基本操作:
    pop()   弹出栈顶元素
    top()   返回栈顶元素
    push(x) 将元素x压入栈中
    size()  栈中包含的元素个数
    empty() 判断栈是否为空
队列的基本操作:
    pop()   弹出队列首部元素
    front() 返回队列首部元素
    push()
    size()
    empty()

    栈底                栈顶
    队列尾部            队列首部
    1    2    3    4    5

实际上,栈和队列所有基本操作中唯一不同的操作就在于将元素push进vector中
对于栈而言是push到栈顶,对于队列而言是push到队列尾部
而对于其他的基本操作二者都是等同的,
故而唯一需要修改的就是使用队列的push操作实现栈的push操作

C++ 对于queue和stack的top/front和pop() 操作
    pop() 操作的返回值是void,仅仅实现删除元素的功能,不返回任何元素
    top/front 操作的返回值返回栈顶元素

假设现在栈中元素为
    栈底           栈顶
    1    2    3    4
则希望将元素5入栈后:
    栈底                栈顶
    1    2    3    4    5
实现过程:
step1:
    先将元素5push进入helper_queue辅助队列中
step2:
    再将当前队列/栈中的元素(由队列首部/栈顶到队列尾部/栈底,分别为 1 2 3 4)
    从队列首部到队列尾部依次弹出队列并push到helper_queue的队列尾部
    helper_queue
    队列尾部
    1             2             3          4        5
step3:
    再将helper_queue队列中的元素从队列首部至队列尾部依次从队列中弹出
    并添加到原始的栈/队列中,
**/
#include<vector>
#include<queue>
using namespace std;
class MyStack {
private:
    queue<int> stack_seq;
public:
    /** Initialize your data structure here. */
    MyStack() {

    }

    /** Push element x onto stack. */
    void push(int x) {
        queue<int> helper_queue;
        helper_queue.push(x);
        int length=this->stack_seq.size();
        while(length>0){
            length--;
            int value;
            value=this->stack_seq.front();
            this->stack_seq.pop();
            helper_queue.push(value);
        }
        int new_length=helper_queue.size();
        while(new_length>0){
            new_length--;
            int value=helper_queue.front();
            helper_queue.pop();
            this->stack_seq.push(value);
        }
    }

    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        int result=this->stack_seq.front();
        this->stack_seq.pop();
        return result;
    }

    /** Get the top element. */
    int top() {
        return this->stack_seq.front();
    }

    /** Returns whether the stack is empty. */
    bool empty() {
        return this->stack_seq.empty();
    }
};

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack* obj = new MyStack();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->top();
 * bool param_4 = obj->empty();
 */
/**
leetcode 232. 用栈实现队列
使用栈实现队列的下列操作:
    push(x) -- 将一个元素放入队列的尾部。
    pop() -- 从队列首部移除元素。
    peek() -- 返回队列首部的元素。
    empty() -- 返回队列是否为空。
栈的push操作是将元素添加到栈顶
队列的push操作是将元素添加到队列尾部
**/

#include<stack>
using namespace std;

class MyQueue {
private:
    stack<int> queue_seq;
public:
    /** Initialize your data structure here. */
    MyQueue() {

    }

    /** Push element x to the back of queue. */
    void push(int x) {
        // step1: 构造辅助栈,从原始的栈中依次弹出栈顶元素并push到辅助栈中
        stack<int> helper_stack;
        // step2: 将x push到辅助栈中
        while(!this->queue_seq.empty()){
            helper_stack.push(this->queue_seq.top());
            this->queue_seq.pop();
        }
        helper_stack.push(x);
        // step3: 将辅助栈中的元素依次弹出并push到原始的队列中
        while(!helper_stack.empty()){
            this->queue_seq.push(helper_stack.top());
            helper_stack.pop();
        }
    }

    /** Removes the element from in front of queue and returns that element. */
    int pop() {
        int value=this->queue_seq.top();
        this->queue_seq.pop();
        return value;
    }

    /** Get the front element. */
    int peek() {
        return this->queue_seq.top();
    }

    /** Returns whether the queue is empty. */
    bool empty() {
        return this->queue_seq.empty();
    }
};

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue* obj = new MyQueue();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->peek();
 * bool param_4 = obj->empty();
 */
/**
leetcode 155. 最小栈
设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。
    push(x) -- 将元素 x 推入栈中
    pop() -- 删除栈顶的元素
    top() -- 获取栈顶元素
    getMin() -- 检索栈中的最小元素
**/
using namespace std;
#include<stack>
#include<iostream>
#include<vector>
class MinStack {
private:
    stack<int> stack_seq;
    vector<int> min_value;
public:
    /** initialize your data structure here. */
    MinStack() {
        min_value.push_back(0x7fffffff);
    }

    void push(int x) {
        // 插入排序法
        this->stack_seq.push(x);
        for(unsigned int i=0;i<this->min_value.size();i++){
            if(this->min_value[i]<=x){
                this->min_value.insert(this->min_value.begin()+i,x);
                return;
            }
        }
        this->min_value.push_back(x);
        return;
    }

    void pop() {
        // 从栈中删除元素
        int value=this->stack_seq.top();
        this->stack_seq.pop();
        for(unsigned int i=0;i<this->min_value.size();i++){
            if(this->min_value[i]==value){
                this->min_value.erase(this->min_value.begin()+i);
                return;
            }
        }
    }

    int top() {
        return this->stack_seq.top();
    }

    int getMin() {
        return this->min_value[this->min_value.size()-1];
    }
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack* obj = new MinStack();
 * obj->push(x);
 * obj->pop();
 * int param_3 = obj->top();
 * int param_4 = obj->getMin();
 */

 int main(){
    MinStack minStack;
    minStack.push(-2);
    minStack.push(0);
    minStack.push(-3);
    cout<<minStack.getMin()<<endl;   //--> 返回 -3.
    minStack.pop();
    cout<<minStack.top()<<endl;      //--> 返回 0.
    cout<<minStack.getMin()<<endl;   //--> 返回 -2

    return 0;
 }

上述操作的时间复杂度是O(n)级别,题目要求的是O(1)级别

/**
leetcode 155. 最小栈
设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。
    push(x) -- 将元素 x 推入栈中
    pop() -- 删除栈顶的元素
    top() -- 获取栈顶元素
    getMin() -- 检索栈中的最小元素

构造最小值栈,记录栈在每个状态下的最小值
**/
using namespace std;
#include<stack>
#include<iostream>
#include<vector>
class MinStack {
private:
    stack<int> stack_seq;
    stack<int> min_stack;
public:
    /** initialize your data structure here. */
    MinStack() {

    }

    void push(int x) {
        this->stack_seq.push(x);
        if(this->min_stack.empty()){
            this->min_stack.push(x);
            return;
        }
        if(x<=this->min_stack.top()){
            this->min_stack.push(x);
        }
        else{
            this->min_stack.push(this->min_stack.top());
        }
        return;
    }

    void pop() {
        // 从栈中删除元素
        this->stack_seq.pop();
        this->min_stack.pop();
    }

    int top() {
        return this->stack_seq.top();
    }

    int getMin() {
        return this->min_stack.top();
    }
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack* obj = new MinStack();
 * obj->push(x);
 * obj->pop();
 * int param_3 = obj->top();
 * int param_4 = obj->getMin();
 */

 int main(){
    MinStack minStack;
    minStack.push(-2);
    minStack.push(0);
    minStack.push(-3);
    cout<<minStack.getMin()<<endl;   //--> 返回 -3.
    minStack.pop();
    cout<<minStack.top()<<endl;      //--> 返回 0.
    cout<<minStack.getMin()<<endl;   //--> 返回 -2

    return 0;
 }
// http://poj.org/submit?problem_id=1363
#include<stack>
#include<iostream>
#include<vector>
#include<queue>
using namespace std;

// input_seq也可以用队列实现

bool is_valid(int num,vector<int > input_seq){
    // 模拟出栈和入栈的过程
    // 关键是要明确在输入序列中,哪些元素在辅助栈内部,哪些元素在辅助栈外部
    stack<int> helper_stack;// 初始化辅助栈
    queue<int> outside_seq;// 表示在辅助栈外部的辅助队列/也可以用vector实现
    for(int i=1;i<=num;i++){
        outside_seq.push(i);//向队列尾部添加元素
    }
    int index=0;
    while(1){
        if(helper_stack.empty() or helper_stack.top()!=input_seq[index]){
            if(!outside_seq.empty()){
                helper_stack.push(outside_seq.front());
                outside_seq.pop();
            }
            else{
                return false;
            }
        }
        else{
            helper_stack.pop();
            index++;
        }
        if(index==num){
            return true;
        }
    }
}

int main(){
    vector<string> output_seq;
    while(1){
        int num;
        cin>>num;
        if(num==0){
            break;
        }
        else
        {
            while(1){
                int first_num;
                cin>>first_num;
                if(first_num==0){
                    output_seq.push_back("\n");
                    break;
                }

                vector<int> input_seq;
                input_seq.push_back(first_num);
                for(int i=2;i<=num;i++){
                    int temp_num;
                    cin>>temp_num;
                    input_seq.push_back(temp_num);
                }
                if(is_valid(num,input_seq)==true){
                    output_seq.push_back("Yes");
                }
                else{
                    output_seq.push_back("No");
                }
            }
        }
    }
    for(int j=0;j<output_seq.size();j++){
        cout<<output_seq[j]<<endl;
    }
    return 0;//
}
/**
leetcode 224. 基本计算器
实现一个基本的计算器来计算一个简单的字符串表达式的值。
字符串表达式可以包含左括号 ( ,右括号 ),加号 + ,减号 -,非负整数和空格

运算优先级  (  +/-   )

首先将中缀表达式转换成后缀表达式

构造操作符栈和操作数栈
对于操作数栈: 扫描输入的字符串,遇到操作数即入栈
对于操作符栈: 根据当前扫描到的操作符优先级决定对于当前的操作符进行出栈还是入栈
               (  )左括号,右括号,优先级最低
                +  - 优先级相等
               如果当前扫描到的运算符的优先级比栈顶优先级低或者相等,说明栈顶元素/运算符的出栈时间已到
               则将栈顶运算符出栈,并从操作数栈中取出相应的操作数进行计算
可以使用栈的数据结构消除字符串中的括号
**/
#include<string>
#include<iostream>
#include<stack>
using namespace std;
class Solution {
public:
    int calculate(string s) {
        stack<char> operator_stack;
        stack<int> operand_stack;
        int right_num;
        int left_num;
        bool last_num=false;// 表示上一次扫描到的字符是否是数字
        for(unsigned int i=0;i<s.size();i++){
//            cout<<"index : "<<i<<"value: "<<s[i]<<endl;
//            if(!operand_stack.empty()){
//                cout<<" operand_stack   "<<operand_stack.top()<<"size "<<operand_stack.size()<<endl;
//            }
//            if(!operator_stack.empty()){
//                cout<<" operator_stack  "<<operator_stack.top()<<"size "<<operator_stack.size()<<endl;
//            }

            switch(s[i]){
            case(' ') :
                last_num=false;
                break;
            case('('):
                operator_stack.push('(');
                last_num=false;
                break;
            case(')'):
                last_num=false;
                while(operator_stack.top()!='('){
                        switch(operator_stack.top()){
                        case('+'):
                            operator_stack.pop();
                            right_num=operand_stack.top();
                            operand_stack.pop();
                            left_num=operand_stack.top();
                            operand_stack.pop();
                            operand_stack.push(left_num+right_num);
                            break;
                        case('-'):
                            operator_stack.pop();
                            right_num=operand_stack.top();
                            operand_stack.pop();
                            left_num=operand_stack.top();
                            operand_stack.pop();
                            operand_stack.push(left_num-right_num);
                      }
                }
                operator_stack.pop();
                break;
            case('-'):
            case('+'):
                last_num=false;
                if(operator_stack.empty()){
                    operator_stack.push(s[i]);
                }
                else{
                    switch(operator_stack.top()){
                    case('+'):
                        operator_stack.pop();
                        right_num=operand_stack.top();
                        operand_stack.pop();
                        left_num=operand_stack.top();
                        operand_stack.pop();
                        operand_stack.push(left_num+right_num);
                        operator_stack.push(s[i]);
                        break;
                    case('-'):
                        operator_stack.pop();
                        right_num=operand_stack.top();
                        operand_stack.pop();
                        left_num=operand_stack.top();
                        operand_stack.pop();
                        operand_stack.push(left_num-right_num);

                        operator_stack.push(s[i]);

                        break;
                    case('('):
                        operator_stack.push(s[i]);

                        break;
                    }
                }
                break;
            default:// 说明当前扫描到的字符是数字
                if(last_num==false){
                    operand_stack.push(s[i]-'0');
                }
                else{
                    //将操作数栈的栈顶元素出栈,并乘以10,再加上当前元素再push到操作数栈中
                    int prev_num=operand_stack.top();
                    operand_stack.pop();
                    operand_stack.push(prev_num*10+(s[i]-'0'));
                }
                last_num=true;
            }
        }
        if(operator_stack.empty()){
            return operand_stack.top();
        }
        else{
            char ope=operator_stack.top();
            right_num=operand_stack.top();
            operand_stack.pop();
            left_num=operand_stack.top();
            operand_stack.pop();

            if(ope=='+'){
                return left_num+right_num;
            }
            else{
                return left_num-right_num;
            }
        }
    }
};



int main(){
    string a;
    getline(cin,a);

    Solution s;
    cout<<"input  "<<a<<endl;
    cout<<"calculating result: "<<s.calculate(a)<<endl;
    return 0;
}
/**
二叉堆的属性:
最大/最小二叉堆:是最大/最小值先出的完全二叉树
对于最大二叉堆,堆顶(即二叉树的根节点)是元素值最大的元素
它的左子树和右子树分别都是最大堆
通过弹出堆顶的元素,即可得到完全二叉树的最大元素

二叉堆也被称为优先级队列
STL中的二叉堆:
二叉堆:最大/最小值先出的完全二叉树

big_heap.empty() :  判断堆是否为空
big_heap.pop():     弹出堆顶元素(将堆顶元素弹出后,STL优先级队列的内部算法会对堆的结构进行调整,调整的时间复杂度log(N))
big_heap.push(x)    将元素x插入二叉堆中
big_heap.top()      返回堆顶元素,即二叉堆的最大值
big_heap.size()     返回堆中的元素个数

**/
#include<queue>
#include<iostream>
using namespace std;

int main(){
    priority_queue<int> big_heap;//优先级队列,默认构造是最大堆
    priority_queue<int,vector<int>,greater<int> > small_heap;//最小堆的构造方法
    priority_queue<int,vector<int>,less<int> > big_heap2;//最大堆的构造方法

    if(big_heap.empty()){
        cout<<" big_heap is empty "<<endl;
    }

    int test[]={6,10,1,7,99,4,33};
    for(unsigned int i=0;i<7;i++){
        big_heap.push(test[i]);
    }

    cout<<"big_heap.top()= "<<big_heap.top()<<endl;

    big_heap.push(1000);

    cout<<"big_heap.top()= "<<big_heap.top()<<endl;

    for(int i=0;i<3;i++){
        big_heap.pop();
    }
    cout<<"big_heap.top()= "<<big_heap.top()<<endl;
    cout<<"big_heap.size()= "<<big_heap.size()<<endl;

    return 0;
}

/**
leetcode 215. 数组中的第K个最大元素
在未排序的数组中找到第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,
而不是第 k 个不同的元素。

算法1: 
构造最大堆,利用STL模板库中的优先级队列对输入的无序数组进行排序,再从排序得到的最大堆中
找到第k大的数据,但是这样还是要对N个数据进行排序

**/

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        // 构造最大堆,对优先级队列进行k-1次pop操作后取top元素即可
        priority_queue<int> big_heap;
        for(unsigned int i=0;i<nums.size();i++){
            big_heap.push(nums[i]);
        }
        while(k>1){
            big_heap.pop();
            k--;
        }
        return big_heap.top();
    }
};
/**
leetcode 215. 数组中的第K个最大元素

构造具有K个元素的最小堆,堆中保存的元素是原始数组中前K个最大的元素
则最小堆的堆顶元素就是数组中的第K个最大元素
故而问题转换成如何构建这个最小堆

**/
#include<iostream>
using namespace std;
#include<queue>
#include<vector>
class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        // 构造最大堆,对优先级队列进行k-1次pop操作后取top元素即可
        priority_queue<int,vector<int>,greater<int> > small_heap;
        for(unsigned int i=0;i<nums.size();i++){
            // 对于输入数组中的元素,逐个进行扫描
            if(small_heap.size()<k){
                // 如果最小堆中的元素个数小于k,则直接将元素push到最小堆中
                small_heap.push(nums[i]);
            }
            else{
                // 如果当前元素大于最小堆的堆顶元素,则删除最小堆对顶元素,
                // 将当前元素push进入最小堆
                if(nums[i]>small_heap.top()){
                    small_heap.pop();
                    small_heap.push(nums[i]);
                }
            }
        }
        return small_heap.top();
    }
};
/**
leetcode 215. 数组中的第K个最大元素

构造具有K个元素的最小堆,堆中保存的元素是原始数组中前K个最大的元素
则最小堆的堆顶元素就是数组中的第K个最大元素
故而问题转换成如何构建这个最小堆

C++中如何将数字字符转换成int整型
'8'-'0'=8   int value

**/
#include<iostream>
using namespace std;
#include<queue>
#include<vector>
class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        // 构造最大堆,对优先级队列进行k-1次pop操作后取top元素即可
        priority_queue<int,vector<int>,greater<int> > small_heap;
        for(unsigned int i=0;i<nums.size();i++){
            // 对于输入数组中的元素,逐个进行扫描
            if(small_heap.size()<k){
                // 如果最小堆中的元素个数小于k,则直接将元素push到最小堆中
                small_heap.push(nums[i]);
            }
            else{
                // 如果当前元素大于最小堆的堆顶元素,则删除最小堆对顶元素,
                // 将当前元素push进入最小堆
                if(nums[i]>small_heap.top()){
                    small_heap.pop();
                    small_heap.push(nums[i]);
                }
            }
        }
        return small_heap.top();
    }
};
/**
leetcode 295. 数据流的中位数
中位数是有序列表中间的数
如果列表长度是偶数,中位数则是中间两个数的平均值

**/
#include<iostream>
#include<vector>
using namespace std;
class MedianFinder {
private:
    vector<int> input_seq;
public:
    /** initialize your data structure here. */
    MedianFinder() {
    }

    void addNum(int num) {
        // 将数据push到输入序列的同时对输入序列进行插入排序
        if(input_seq.empty()){
            input_seq.push_back(num);
        }
        else{
                int index=-1;
                for(unsigned int i=0;i<input_seq.size();i++){
                    if(input_seq[i]>=num){
                        index=i;
                        break;
                    }
                }
                if(index==-1){
                    // 说明序列中的所有元素数值都小于当前的数据
                    input_seq.push_back(num);
                }
                else{
                    input_seq.insert(input_seq.begin()+index,num);
                }
        }
        return;
    }

    double findMedian() {
        int mid=input_seq.size()/2;
        if(input_seq.size()%2==0){
            return (input_seq[mid]+input_seq[mid-1])/2.0;
        }
        else{
            return input_seq[mid]*1.0;
        }
    }
};

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder* obj = new MedianFinder();
 * obj->addNum(num);
 * double param_2 = obj->findMedian();
 */

 int main(){
    MedianFinder a;
    a.addNum(1);
    a.addNum(2);
    cout<<a.findMedian()<<endl;// -> 1.5
    a.addNum(3);
    cout<<a.findMedian()<<endl;// -> 2

    return 0;
 }
/**
leetcode 295. 数据流的中位数
使用最大最小堆实现

维护一个最大堆和一个最小堆,分别存储输入流数据的一半
所要满足的条件是:
最大堆的堆顶元素要小于最小堆的堆顶元素
由于最大堆的堆顶元素是最大堆中数值最大的元素,
故而这意味着最大堆中的所有元素都小于最小堆的堆顶元素

如果输入流数据中的元素个数为偶数
    则最大堆的元素个数和最小堆的元素个数相等,直接将两个堆顶元素取平均值即可
如果输入流数据中的元素个数为奇数
    则最大堆的元素个数与最小堆的元素个数相差1,
    则将元素个数多的堆顶元素取出即可
故而动态接收输入流数据的过程中,需要维护两个状态:
    最大堆和最小堆的元素之差为1或者0
    最大堆的堆顶元素小于最小堆的堆顶元素

最大堆中存储的是数据流中数值较小的前半部分元素
最小堆中存储的是数据流中数值较大的后半部分元素

总共有如下3种可能的情况
1.small_heap.size()==big_heap.size() 最大最小堆元素个数相等
    (1)如果最大堆中的元素个数为0,说明最大最小堆都为空
       则将数值直接push进入big_heap
    (2)如果最大堆中的元素个数不为0
        3        7
       / \     /  \
      1   2    8  9
      最大堆   最小堆
      case1: num=5 如果新元素小于最小堆的堆顶元素,则直接push进入最大堆中
      case2: num=10 新元素大于最小堆的堆顶元素,则直接push进入最小堆中
2.small_heap.size()>big_heap.size()  最小堆中的元素个数大于最大堆
        2         7
       /         /  \
      1          8  9
      最大堆   最小堆
      case1: num=0  如果新元素小于等于最小堆的堆顶元素,则直接push进入最大堆
      case2: num=10 如果新元素大于最小堆的堆顶元素
             本身应该被push到最小堆中,但是这样最大最小堆中的元素个数不平衡
             将最小堆的堆顶元素push到最大堆中
             删除最小堆的堆顶元素
             将新元素push到最小堆中
                7          8
               / \        / \
              1   2      9  10
              最大堆     最小堆
3.big_heap.size()>small_heap.size()  最大堆中的元素个数大于最小堆
        3       7
       / \     /
      1   2    8
      最大堆   最小堆
      case1:  如果新元素大于或者等于最小堆的堆顶元素,则直接push进入最小堆
      case2:  num=0
              将最大堆的堆顶元素push到最大堆中
              删除最大堆的堆顶元素
              将新元素push到最大堆中
      2       3
     / \     / \
     1  0    7  8
**/
#include<queue>
#include<iostream>
using namespace std;

class MedianFinder {
private:
    priority_queue<int,vector<int>,less<int> > big_heap;// 初始化最大堆
    priority_queue<int,vector<int>,greater<int> > small_heap;//初始化最小堆
public:
    /** initialize your data structure here. */
    MedianFinder() {
    }

    void addNum(int num) {
        if(this->big_heap.size()==this->small_heap.size()){
            // 如果最大堆中的元素个数与最小堆的元素个数相等
            if(this->big_heap.size()==0){
                this->big_heap.push(num);
            }
            else{
                if(num<=this->small_heap.top()){
                    this->big_heap.push(num);
                }
                else{
                    this->small_heap.push(num);
                }
            }
        }
        else{
            if(this->small_heap.size()>this->big_heap.size()){
                if(num<=this->big_heap.top()){
                    this->big_heap.push(num);
                }
                else{
                    if(num>this->big_heap.top() and num<this->small_heap.top()){
                        this->big_heap.push(num);
                    }
                    else{
                        // num比最小堆的堆顶元素更大
                        // 这种情况下本来应该把num push到最小堆,
                        // 但是这样会破坏元素个数的平衡
                        /**
                        1.将最小堆的堆顶元素弹出并push到最大堆中
                        2.将新元素push到最小堆中
                        **/
                        this->big_heap.push(this->small_heap.top());
                        this->small_heap.pop();
                        this->small_heap.push(num);
                    }
                }
            }
            else{
                // 最大堆中的元素个数大于等于最小堆中的元素个数
                if(num>=this->big_heap.top()){
                    this->small_heap.push(num);
                }
                else{
                    this->small_heap.push(this->big_heap.top());
                    this->big_heap.pop();
                    this->big_heap.push(num);
                }
            }
        }
    }

    double findMedian() {
        if(this->small_heap.size()==this->big_heap.size()){
            return (this->small_heap.top()+this->big_heap.top())/2.0;
        }
        else{
            if(this->small_heap.size()>this->big_heap.size()){
                return this->small_heap.top()*1.0;
            }
            else{
                return this->big_heap.top()*1.0;
            }
        }
    }
};

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder* obj = new MedianFinder();
 * obj->addNum(num);
 * double param_2 = obj->findMedian();
 */

 int main(){
    MedianFinder a;
    a.addNum(1);
    a.addNum(2);
    cout<<a.findMedian()<<endl;// -> 1.5
    a.addNum(3);
    cout<<a.findMedian()<<endl;// -> 2

    return 0;
 }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值