C++ stack和queue相关练习题

目录

1.最小栈

2.栈的压入、弹出序列

 3.逆波兰表达式

3.队列实现栈

4.二叉树的层序遍历(运用队列)

5.找出数组中第k大的元素

1.最小栈

力扣

 

删除最小值1后要遍历一遍剩下的数才能找到剩下数里面的最小值 。极端情况下如果数组为降序

 

应该随时记录对应位置的最小值,考虑用双栈(以空间换时间)

 还可以继续优化:minst中没必要push相同的值

 还是存在重复的情况

class MinStack {
public:
    MinStack() {

    }
    
    void push(int val) {
        _st.push(val);
        if(_minst.empty()||val <= _minst.top())
        {
            _minst.push(val);
        }
    }
    
    void pop() {
        if(_st.top() == _minst.top())
        {
            _minst.pop();
        }
        _st.pop(); 
    }
    
    int top() {
        return _st.top();

    }
    
    int getMin() {
        return _minst.top();
    }
private:
    stack<int>_st;
    stack<int>_minst;
};

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

极端场景:假设插入的重复数据很多,能否对minst再优化,让minst中少存储一些重复数据?

struct val_Count
{
    int _val;
    int _count;
};

class MinStack {
public:
    MinStack() {

    }
    
    void push(int val) {
        _st.push(val);
        if(_minst.empty()||val <= _minst.top())
        {
            _minst.push(val);
        }
    }
    
    void pop() {
        if(_st.top() == _minst.top())
        {
            _minst.pop();
        }
        _st.pop(); 
    }
    
    int top() {
        return _st.top();

    }
    
    int getMin() {
        return _minst.top();
    }
private:
    stack<int>_st;
    stack<int>_minst;
};
class MinStack
{
public:
	void push(int x)
	{
		// 只要是压栈,先将元素保存到_elem中
		_elem.push(x);

		// 如果x小于_min中栈顶的元素,将x再压入_min中
		if (_min.empty() || x <= _min.top())
			_min.push(x);
	}

	void pop()
	{
		// 如果_min栈顶的元素等于出栈的元素,_min顶的元素要移除
		if (_min.top() == _elem.top())
			_min.pop();

		_elem.pop();
	}

	int top() { return _elem.top(); }
	int getMin() { return _min.top(); }
private:
	// 保存栈中的元素
	std::stack<int> _elem;

	// 保存栈的最小值
	std::stack<int> _min;
};

2.栈的压入、弹出序列

思路:

 

 使用栈的入栈和出栈来模拟这个出栈顺序,如果能模拟出来,就说明是合法的,如果不能模拟,就不是合法的

1.先把push数组中的值入栈

2.pop数组的值跟栈里面的数据比较,如果相等,则pop数组往后走,不断出栈里面的数据,直到不相等或者栈为空,重复第一步即可

结束条件:push数组走完就结束

判断是否匹配:如果pop数组走完了,就是匹配的;如果pop数组没走完,就是不匹配的

class Solution {
public:
    bool IsPopOrder(vector<int> pushV,vector<int> popV) {
        stack<int>st;
        int i = 0;
        int j = 0;
        while(i<pushV.size())
        {
            st.push(pushV[i]);
            ++i;
            while(!st.empty()&&st.top() == popV[j])
            {
                st.pop();
                ++j;
            }
        }
        
        return j == popV.size();
        
    }
};
class Solution {
public:
	bool IsPopOrder(vector<int>pushV, vector<int>popV) {
		stack<int>st;
		for (auto e : pushV)
		{
			st.push(e);
			while (!st.empty()&&st.top()==popV[popi])//返回栈顶元素,判空
			{
				++popi;
				st.pop();
			}
		}
		//return popi = popV.size();
		return st.empty();
	}
};
class Solution {
public:
	bool IsPopOrder(vector<int> pushV, vector<int> popV) {
		//入栈和出栈的元素个数必须相同
		if (pushV.size() != popV.size())
			return false;

		// 用s来模拟入栈与出栈的过程
		int outIdx = 0;
		int inIdx = 0;
		stack<int> s;

		while (outIdx < popV.size())
		{
			// 如果s是空,或者栈顶元素与出栈的元素不相等,就入栈
			while (s.empty() || s.top() != popV[outIdx])
			{
				if (inIdx < pushV.size())
					s.push(pushV[inIdx++]);
				else
					return false;
			}

			// 栈顶元素与出栈的元素相等,出栈
			s.pop();
			outIdx++;
		}

		return true;
	}
};

 

 3.逆波兰表达式

 中缀表达式如何转换成后缀表达式?

 

class Solution {
public:
    void getOPNum(stack<int>& st,int& left,int& right)
    {
        right = st.top();
        st.pop();
        left = st.top();
        st.pop();
    }
    int evalRPN(vector<string>& tokens) {
        stack<int> st;
        for(const auto& str:tokens)
        {
            int left,right;
            switch(str[0])//或者用str.back()
            {
                case '+':
                    getOPNum(st,left,right);
                    st.push(left + right);
                    break;
                case '-':
                if(str.size() == 1)
                {
                    getOPNum(st,left,right);
                    st.push(left - right);
                    break;
                }
                else
                {
                    st.push(stoi(str));
                }
                break;
                case '*':
                  getOPNum(st,left,right);
                    st.push(left * right);
                    break;
                case '/':
                  getOPNum(st,left,right);
                    st.push(left / right);
                    break;
                default:
                    st.push(stoi(str));
                break;
            }   
        }
        return st.top();
    }
};

class Solution {
public:
	int evalRPN(vector<string>& tokens) {
		stack<int> s;
		for (size_t i = 0; i < tokens.size(); ++i)
		{
			string& str = tokens[i];
			// str为数字
			if (!("+" == str || "-" == str || "*" == str || "/" == str))
			{
				s.push(atoi(str.c_str()));
			}
			else
			{
				// str为操作符
				int right = s.top();
				s.pop();
				int left = s.top();
				s.pop();
				switch (str[0])
				{
				case '+':
					s.push(left + right);
					break;
				case '-':
					s.push(left - right);
					break;
				case '*':
					s.push(left * right);
					break;
				case '/':
					// 题目说明了不存在除数为0的情况
					s.push(left / right);
					break;
				}
			}
		}
		return s.top();
	}
};
class Solution {
public:
	int evalRPN(vector<string>& tokens) {
		stack<int> st;
		for (auto str : tokens)
		{
			if (str[0] == "+" || str == "-"
				|| str == "*" || str == "/")
			{
				//取出两个操作数准备运算
				int right = st.top();
				st.pop();
				int left = st.top();
				st.pop();

				switch (str[0])
				{
				case'+':
					st.push(left + right);
					break;
				case'-':
					st.push(left - right);
					break;
				case'*':
					st.push(left * right);
					break;
				case'/':
					st.push(left / right);
					break;
				default:
					break;
				}
			}
			else
			{
				st.push(stoi(str));//stoi函数:把字符串转换成int输出
			}
		}

		return st.top();
	}
};

3.队列实现栈

力扣

class MyStack {
public:
    MyStack() {

    }
    
    void push(int x) {
        if(!_q1.empty())
        {
            _q1.push(x);
        }
        else
        {
            _q2.push(x);
        }
    }
    
    int pop() {
        queue<int>*emptyQ = &_q1;
        queue<int>*nonemptyQ = &_q2;
        if(!_q1.empty())
        {
            swap(emptyQ,nonemptyQ);
        }
        while(nonemptyQ->size()>1)
        {
            emptyQ->push(nonemptyQ->front());
            nonemptyQ->pop();
        }

        int top = nonemptyQ->front();
        nonemptyQ->pop();
        return top;
    }
    
    int top() {//取栈顶数据
        if(!_q1.empty())
        {
            return _q1.back();
        }
        else
        {
            return _q2.back();
        }
    }
    
    bool empty() {
        return _q1.empty()&&_q2.empty();
    }
    queue<int>_q1;
    queue<int>_q2;
};

4.二叉树的层序遍历(运用队列)

 力扣

 

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*>q;
        int levelSize;
        if(root)
        {
            q.push(root);
            levelSize = 1;
        }
        vector<vector<int>>vv;

        while(!q.empty())
        {
            //控制着,一层一层出
            vector<int>v;
            for(int i  = 0;i<levelSize;++i)
            {
                TreeNode*front = q.front();
                q.pop();
                v.push_back(front->val);
                //一个节点出来要把其下一层数据代入
                if(front->left)
                {
                    q.push(front->left);
                }
                if(front->right)
                {
                    q.push(front->right);
                }
            }
            //上一层出完了,下一层就都入队列了,队列size就是下一层的数据个数
            levelSize = q.size();
            vv.push_back(v);
        }
        return vv;
    }
};

 return之前加上reverse(vv.begin(),vv.end()); 即可实现从下往上层序遍历

5.找出数组中第k大的元素

力扣

 法一

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        sort(nums.begin(),nums.end());
        return nums[nums.size()-k];
    }
};

法二:


class Solution {
public:
	int findKthLargest(vector<int>& nums, int k) {
		// 将数组中的元素先放入优先级队列中
		priority_queue<int> p(nums.begin(), nums.end());

		// 将优先级队列中前k-1个元素删除掉
		for (int i = 0; i < k - 1; ++i)
		{
			p.pop();
		}

		return p.top();
	}
};

 时间复杂度:O(N+k*logN)

空间复杂度:O(N)

法三:传反向迭代器即为降序

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        sort(nums.rbegin(),nums.rend());
        return nums[k-1];
    }
};


 

法四

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        sort(nums.begin(),nums.end(),greater<int>());//greater<int>后面要加括号,类型后面加上括号就是对象
        return nums[k-1];
    }
};

法五

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
         //k个小堆
         priority_queue<int,vector<int>,greater<int>>kMinHeap(nums.begin(),nums.begin()+k);

         for(size_t i = k;i<nums.size();++i)
         {
             if(nums[i] > kMinHeap.top())
             {
                 kMinHeap.pop();
                 kMinHeap.push(nums[i]);
             }
         }

         return kMinHeap.top();
          
    }
};


 

时间复杂度:O(K+(N-K)*logK)

空间复杂度:  O(K)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值