目录
232.用栈实现队列
题目:
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(
push
、pop
、peek
、empty
):实现
MyQueue
类:
void push(int x)
将元素 x 推到队列的末尾int pop()
从队列的开头移除并返回元素int peek()
返回队列开头的元素boolean empty()
如果队列为空,返回true
;否则,返回false
说明:
- 你 只能 使用标准的栈操作 —— 也就是只有
push to top
,peek/pop from top
,size
, 和is empty
操作是合法的。- 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
假设有这样一个队列,队首元素为1,队尾元素为5 。
我们用两个栈来分别模拟入队和出队操作:
入队时,就将数据压入栈1,此时栈顶时队尾元素;出队时,将栈1的元素全部压入栈2中,此时栈顶是队首元素,再进行出栈操作,这样就模拟实现了队列的先入先出。
注意:当出队栈为空时,才需要将入队栈元素压入
解答:
class MyQueue {
public:
MyQueue() {
while(!_push.empty()){
_push.pop();
}
while(!_pop.empty()){
_pop.pop();
}
}
void push(int x) {
_push.push(x);
}
int pop() {
if(_pop.empty()){
while(!_push.empty()){
_pop.push(_push.top());
_push.pop();
}
}
int ret = _pop.top();
_pop.pop();
return ret;
}
int peek() {
if(_pop.empty()){
while(!_push.empty()){
_pop.push(_push.top());
_push.pop();
}
}
return _pop.top();
}
bool empty() {
if(_push.empty() && _pop.empty())
return true;
return false;
}
private:
stack<int> _push;
stack<int> _pop;
};
225.用队列实现栈
题目:
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(
push
、top
、pop
和empty
)。实现
MyStack
类:
void push(int x)
将元素 x 压入栈顶。int pop()
移除并返回栈顶元素。int top()
返回栈顶元素。boolean empty()
如果栈是空的,返回true
;否则,返回false
。注意:
- 你只能使用队列的标准操作 —— 也就是
push to back
、peek/pop from front
、size
和is empty
这些操作。- 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
假设入栈5个元素,栈顶元素是5。
我们将这五个元素全部排进队列1,此时栈顶元素在队尾;当我们需要出栈时,就将除队尾元素之外的全部元素排进队列2中,此时栈顶元素来到了队首,再进行出队,这样就模拟实现了栈的后入先出。
解答:
class MyStack {
public:
MyStack() {
while(!_q.empty()){
_q.pop();
}
}
void push(int x) {
_q.push(x);
}
int pop() {
int ret = _q.back();
queue<int> tmp;
while(_q.size() != 1){
tmp.push(_q.front());
_q.pop();
}
_q.pop();
while(!tmp.empty()){
_q.push(tmp.front());
tmp.pop();
}
return ret;
}
int top() {
return _q.back();
}
bool empty() {
return _q.empty();
}
private:
queue<int> _q;
};
155.最小栈
题目:
设计一个支持
push
,pop
,top
操作,并能在常数时间内检索到最小元素的栈。实现
MinStack
类:
MinStack()
初始化堆栈对象。void push(int val)
将元素val推入堆栈。void pop()
删除堆栈顶部的元素。int top()
获取堆栈顶部的元素。int getMin()
获取堆栈中的最小元素。
stack是一种后进先出的特殊线性数据结构,因此只要具有push_back()和pop_back()操作的线性结构,都可以作为stack的底层容器,vector和list都可以,但是题目要求能在常数时间内检索到最小元素,所以我们选择vector:
class MinStack {
public:
MinStack() {
_stack.clear();
}
void push(int val) {
_stack.push_back(val);
}
void pop() {
_stack.pop_back();
}
int top() {
return _stack.back();
}
int getMin() {
vector<int> temp(_stack);
sort(temp.begin(), temp.end());
return temp[0];
}
private:
vector<int> _stack;
};
牛客JZ31.栈的压入、弹出序列
题目:
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
1. 0<=pushV.length == popV.length <=1000
2. -1000<=pushV[i]<=1000
3. pushV 的所有数字均不相同
我们需要一个stack栈来演示压栈过程。
定义两个迭代器,分别指向两个vector的首元素,iterator_pop指向的元素就是下一个出栈的元素,Iiterator_push指向的元素就是下一个入栈的元素,当两者指向的元素值不同时,就继续入栈,并挪动iterator_push;当两者指向值相同时就表示需要出栈,出栈后挪动iterator_pop。
如果最后iterator_pop来到了容器尾,同时stack中没有元素(全部出栈),就说明vector_pop是vector_piush的弹出序列
是弹出序列的情况:
不是弹出序列的情况:
当然,两个序列如果元素个数不一致,就肯定不是压入、弹出序列
解答:
bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {
if (pushV.size() != popV.size())
return false;
auto push = pushV.begin();
auto pop = popV.begin();
stack<int> s;
while (pop != popV.end()) {
if (s.size() == 0 || s.top() != *pop) {
s.push(*push);
++push;
}
if(s.top() == *pop) {
s.pop();
++pop;
}
}
if (s.size())
return false;
return true;
}
};
150.逆波兰表达式求值
题目:
给你一个字符串数组
tokens
,表示一个根据 逆波兰表示法 表示的算术表达式。请你计算该表达式。返回一个表示表达式值的整数。
注意:
- 有效的算符为
'+'
、'-'
、'*'
和'/'
。- 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
- 两个整数之间的除法总是 向零截断 。
- 表达式中不含除零运算。
- 输入是一个根据逆波兰表示法表示的算术表达式。
- 答案及所有中间计算结果可以用 32 位 整数表示。
假设字符串数组为: ["2","1","+","3","*"]
我们遍历这个数组,当遇到运算符"+"时,需要对“+”之前的两个数进行“+”操作,遇到“*”运算符时,需要将“3”以及前面相加的结果进行“*”操作,转换成算数表达式:((2 + 1) * 3) = 9。
可以观察到,每次遍历到运算符时,需要将连同运算符及其前两个数的三个字符进行算数操作,并将结果保存到当前遍历位置,这不就是我们熟悉的入栈出栈的操作吗,这题我们用stack来解决。
遍历数组,依次将字符入栈,遇到运算符就将三个字符出栈,并转化成算数表达式运算,之后将结果以字符形式继续入栈,继续遍历数组,直到遍历结束。
解答:
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<string> s;
string ope;
int left, right;
auto push = tokens.begin();
s.push(*push);
++push;
while (1) {
if (s.size() == 1 && push == tokens.end())
return std::stoi(s.top());
if (s.top() != "+" && s.top() != "-" && s.top() != "*" && s.top() != "/") {
s.push(*push);
++push;
}
else {
ope = s.top();
s.pop();
right = std::stoi(s.top());
s.pop();
left = std::stoi(s.top());
s.pop();
if (ope == "+")
s.push(to_string(left + right));
if (ope == "-")
s.push(to_string(left - right));
if (ope == "*")
s.push(to_string(left * right));
if (ope == "/")
s.push(to_string(left / right));
}
}
}
};
熟练掌握stack和queue容器适配器,对解决一些特定问题有很大帮助。
以上就是我整理的一些关于栈和队列的oj题解,欢迎在评论区留言,觉得这篇博客对你有帮助的,可以点赞收藏关注支持一波~😉