二、队列,栈,堆(小象)

目录

225.用队列实现栈

232.用栈实现队列

155.最小栈

例题4.合法的出栈序列

224.基础计数器

STL优先级队列构造堆

215.数组中第K个最大的元素

295.数据流的中位数


225.用队列实现栈

思考:队列的特性先进先出,栈后进先出,所以用一个临时temp_queue来添加新的元素,再把所有元素都导入到原始的queue之中,那么删除就正好是最新插入的元素了。

class MyStack {
public:
    /** Initialize your data structure here. */
    MyStack() {
        
    }
    queue<int> obj;
    /** Push element x onto stack. */
    void push(int x) {
        queue<int> temp_queue;
        temp_queue.push(x);
        while(!obj.empty()){
            temp_queue.push(obj.front());
            obj.pop();
            //一开始没有pop导致超时了,把栈和队列想的和链表一样
            //以为会覆盖值,后来想想不一样,它直接向后继续添加了。
        }
        while(!temp_queue.empty()){
            obj.push(temp_queue.front());
            temp_queue.pop();
        }
        
    }
    
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        int x = obj.front();
        obj.pop();
        return x;
    }
    
    /** Get the top element. */
    int top() {
        return obj.front();
    }
    
    /** Returns whether the stack is empty. */
    bool empty() {
        return obj.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();
 */

232.用栈实现队列

class MyQueue {
public:
    /** Initialize your data structure here. */
    MyQueue() {
        
    }
    stack<int> data;
    stack<int> temp_stack;
    /** Push element x to the back of queue. */
    void push(int x) {
        while(!data.empty()){
            temp_stack.push(data.top());
            data.pop();
        }
        temp_stack.push(x);
        while(!temp_stack.empty()){
            data.push(temp_stack.top());
            temp_stack.pop();
        }
    }
    
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
        int x = data.top();
        data.pop();
        return x;
    }
    
    /** Get the front element. */
    int peek() {
        return data.top();
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {
        return data.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();
 */

155.最小栈

思考:如果用一个元素minOfStack来存储最小值,在添加的时候没有问题;可是在删除的时候就会存在恰好是最小的那个元素呗删除了,那么此时最小值仍然是被删除的元素就发生了错误。并且如果是用遍历栈来查询最小值,那么时间复杂度就不是O(1)。所以可以构造一个临时存储最小值的栈,栈中每一个位正好对应当前情况下栈的最小值。

编程的技巧:当一个操作无论在条件发生不发生的时候都会执行,可以放在条件语句之外。

例如:当前添加元素x如果大于min_stack_top,就把x赋值为min_stack_top;如果小于则直接添加;因为无论小于还是大于都要添加一个新的元素到min_stack_top。

class MinStack {
public:
    /** initialize your data structure here. */
    MinStack() {
        
    }
    stack<int> stack_data;
    stack<int> min_stack;
    void push(int x) {
        stack_data.push(x);
        if(min_stack.empty()){
            min_stack.push(x);
        }
        else{
            if(x > min_stack.top()){
               x =  min_stack.top() ;  //关键!
            }
            min_stack.push(x);
        }
    }
    
    void pop() {
        stack_data.pop();
        min_stack.pop();
    }
    
    int top() {
        return stack_data.top();
    }
    
    int getMin() {
        return 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();
 */

例题4.合法的出栈序列

思考:使用栈和队列来模拟入栈和出栈的过程。

用队列来存储出栈序列,然后用栈来模拟出栈入栈的过程,因为出战序列的第一位肯定是栈中的top元素,所以每次只用对比top元素和出战序列的front,两者相等就同时弹出,否则就再入栈。

#include<stack>
#include<queue>
bool check_is_valid_order(queue<int> &order)
{
    stack<int> s;
    int num = order.size();
    for(int i =1 ;i <= num;i++){
        s.push(i);
        // while(order.front()==s.top()) 如果栈已经弹空了,队列也是空了,都是NULL,继续弹出就会出错,所以修改下列。
        while(order.front()==s.top()&&!s.empty()){
                s.pop();
                oder.pop();
          }
    }
    if(!s.empty()){
        return false;        
    }
    return true;
}

224.基础计数器

思考:画出有穷状态机就可以解决了。

class Solution {
public:
    void compute(stack<int> &numbers,stack<char> &operation){
        if(numbers.size()<2){
            return ;
        }
        int num2 = numbers.top();
        numbers.pop();
        int num1 = numbers.top();
        numbers.pop();
        if(operation.top() == '+'){
            numbers.push(num1 + num2);
        }
        else if(operation.top() == '-') {
             numbers.push(num1 - num2);
        }
        operation.pop();
    }
    int calculate(string s) {
        static const int BEGIN_STATE = 0;
        static const int NUMBER_STATE = 1;
        static const int OPERATOR_STATE = 2;
        stack<int> numbers_stack;
        stack<char> operation_stack;
        int number = 0;
        int STATE = BEGIN_STATE;
        int compute_flag = 0;
        //遇到数字和+-的时候才有用 才需要推格操作
        for(int i = 0;i<s.size();i++){
            if(s[i] == ' '){
                continue;
            }
            switch(STATE){
                case BEGIN_STATE:
                    if(s[i]>='0' && s[i]<='9'){
                        STATE = NUMBER_STATE;
                    }
                    else{
                        STATE = OPERATOR_STATE;
                    }
                    i--;
                    break;
                case NUMBER_STATE:
                    if(s[i]>='0' && s[i]<='9'){
                        number = number * 10 + s[i] - '0';
                    }
                    //'123'字符串在把他变成了数字之后状态仍然没有改变。
                    //所以判断compute_flag
                    else{
                        numbers_stack.push(number);
                        if(compute_flag==1){
                            compute(numbers_stack,operation_stack);
                        }
                        //如果字符串第一个'123'此时compute_flag = 0 前面没有数字不能计算。
                        number = 0;
                        i--;
                        STATE = OPERATOR_STATE;
                    }
                    break;
                case OPERATOR_STATE:
                    if(s[i]== '+'||s[i] == '-'){
                        operation_stack.push(s[i]);
                        compute_flag = 1;
                    }
                    else if(s[i]=='('){
                         STATE = NUMBER_STATE;
                           compute_flag = 0;
                    }
                    else if(s[i]>='0' && s[i]<='9'){
                        STATE = NUMBER_STATE;
                        i--;
                    }
                    else if(s[i]==')'){
                       compute(numbers_stack,operation_stack);
                    }
                    break;
            }
        }
        if(number!=0){
              numbers_stack.push(number);
              compute(numbers_stack,operation_stack);
        }
        if(number==0 && numbers_stack.empty()){
            return 0;
        }
        return numbers_stack.top();
    }
};

STL优先级队列构造堆

priority_queue<int> heap; //构造默认堆
priority_queue<int,vector<int>,greater<int>> small_heap; //构造默认最小堆
priority_queue<int,vector<int>,less<int>> big_heap; //构造默认最大堆
int test[] = {61,2,4,5,6,7,9,0};
vector<int>  vec(test,test+8); 
	

  
for( unsigned int i = 0;i < vec.size();i++){
		big_heap.push(vec.at(i));
	}
	
for(unsigned int i = 0;i < vec.size();i++){
		cout<<big_heap.top()<<endl;
		big_heap.pop();
	}

遇到的问题和积累:

1error “<”: 有符号/无符号不匹配 
答:”detector 是一个Vector容器 ,detecot.size() 在容器说明中 被定义为: unsigned int 类型, 而j是int 类型,所以会出现: 有符号/无符号不匹配警告,修改int i -->>  unsigned int / size_t

2.error:  error C2065: “cout”: 未声明的标识符 error C2065: “endl”: 未声明的标识符
答:没#include<iostream> ,之后再using namespace std

3.vector 两种访问 1、数组 2、 vec.at(i) //这种会检测访问越界

4.big_heap[8](61,6,9,2,5,4,7,0)    这个排序和按照二叉树 而不是数组的排序 pop()检查过才知道

 

215.数组中第K个最大的元素

思考: 第k大 用最小堆来处理,直接输出堆顶元素,保证最小堆有k个元素,那么堆顶元素是第k个元素中最小的,就是整个vector中第k大的。这里我一开始写的想用两个for循环,第一次是存储k个元素的堆;第二次是和堆顶元素进行比较。后来看了别人的代码,哇,深感自己太不会变通了。直接一次循环就可以了!~

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
      priority_queue<int,vector<int>,greater<int>>  small_heap;
        for(int i = 0; i <nums.size();i++){
            if(i<k){
                 small_heap.push(nums[i]);
            }
            else if(nums[i] > small_heap.top()){
                 small_heap.pop();
                 small_heap.push(nums[i]);
            }
        }
        return small_heap.top();
    }
};

295.数据流的中位数

思考:

class MedianFinder {
public:
    /** initialize your data structure here. */
    MedianFinder() {
        
    }
    //如果你用了else if 语句,当你条件满足时就不会再往下继续判断条件了;
    //而if语句会把每一个条件都判断一下。
    
    //两个约束:1、最大堆的堆顶小于最小堆的堆顶,这样就把数据流中间的数字找到了
    //2、两个堆之间的数目相差不超过1
    void addNum(int num) {
        if(big_heap.empty()){
            big_heap.push(num);
            return ;
        }
        if(small_heap.size()==big_heap.size()){
            //既然要存储到big_heap,那么肯定是和big_heap的堆顶比较,只要小于就说明属于这一半。
            if(num < big_heap.top()){
                big_heap.push(num);
            }
            else {
                small_heap.push(num);
            }

        }
        else if(small_heap.size() > big_heap.size()){
            if(num >= small_heap.top()){
               big_heap.push(small_heap.top());
                  small_heap.pop();//又当做链表直接覆盖了,这里如果你不把top()弹出来,
                //那么你这个堆里面就多了一个元素呀。
                small_heap.push(num);
            }
            else{
                  big_heap.push(num);
            }
        }
        else if(small_heap.size() < big_heap.size()){
           if(num <=big_heap.top()){
               small_heap.push(big_heap.top());
               big_heap.pop();
               big_heap.push(num);
           }
            else{
                small_heap.push(num);
            }
        }
    }
    
    double findMedian() {
        if(small_heap.size()==big_heap.size()){
           return  (small_heap.top() + big_heap.top())/2;
        }
        else if(small_heap.size() > big_heap.size()){
           return  small_heap.top();
        }
        
        return big_heap.top();
    }
    priority_queue<double,vector<double>,greater<double>> small_heap;
    priority_queue<double,vector<double>,less<double> > big_heap;
	//最小堆和最大堆定义反了!!!debug半天!
};

总结:这个代码真调了无数次。。。

1、第一个错误,当small_heap 和 big_heap 中的数 相等的时候,就只用判断num和small_heap.top()和big_heap.top()大小,如果大于small_heap.top(),肯定属于small_heap,直接插入,反之亦然。

2、优先队列 priority_queue<double,vector<double>,greater<double>> small_heap;定义的时候出错了,第一个把数据类型弄成了int,导致输出的中位数出错了;第二个是排序错了,把两个正好弄反了,应该是最大堆,对应的递减啊!最小堆对应的递增啊!想下就清楚了!~!~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值