栈与队列理论基础
栈是以底层容器完成其所有的工作,对外提供统一的接口,底层容器是可插拔的(也就是说我们可以控制使用哪种容器来实现栈的功能)。
用栈实现队列
这是一个什么问题
用栈实现队列的 push pop peek(返回队列的首部元素) empty
思路
用两个栈来实现队列,一个输入栈一个输出栈
push就把数放入输入栈中,
pop,两种情况,一种是输出栈为空,这时候就把输入栈中的所有数都压入输出栈中,这样就把顺序调换了,这时候输出栈的第一个数就是模拟队列的首元素,也就是一开始进入模拟队列的值,也是一开始进入输入栈的值。第二种情况是输出栈不为空,这时候就把输出栈的top输出就好了。
peek和pop一样,就是不对栈进行变动,只查看输出栈的首个元素就行
empty是要看两个栈是否都为空
代码
class MyQueue {
public:
stack<int> stackIn;
stack<int> stackOut;
MyQueue() {
}
void push(int x) {
stackIn.push(x);
}
int pop() {
if (stackOut.empty()) {
while(!stackIn.empty()) {
stackOut.push(stackIn.top());
stackIn.pop();
}
}
int result = stackOut.top();
stackOut.pop();
return result;
}
int peek() {
if (stackOut.empty()) {
while(!stackIn.empty()) {
stackOut.push(stackIn.top());
stackIn.pop();
}
}
return stackOut.top();
}
bool empty() {
if (stackIn.empty() && stackOut.empty()) {
return true;
}
return false;
}
};
用队列来实现栈
思路
一个队列就可以实现栈
push,就直接push就ok
pop 把队列中除去最后一个数之外的所有数按顺序加入队列中,这样顺序就对了
top 和 pop一个思路就是不要弹出去,把最后一个数重新放回队尾
empty就正常判断就好
用result存上结果再pop,利用队列的长度来循环实现pop和top
代码
class MyStack {
public:
queue<int> q1;
MyStack() {
}
void push(int x) {
q1.push(x);
}
int pop() {
int times = q1.size();
for (int i = 0; i < times - 1; i++) {
q1.push(q1.front());
q1.pop();
}
int result = q1.front();
q1.pop();
return result;
}
int top() {
int times = q1.size();
for (int i = 0; i < times - 1; i++) {
q1.push(q1.front());
q1.pop();
}
int result = q1.front();
q1.push(q1.front());
q1.pop();
return result;
}
bool empty() {
if (q1.empty()) {
return true;
}
return false;
}
};
有效的括号
这是一个什么问题
看给的一堆括号,是不是能两两按正确的顺序和方向配对的,顺序是左括号在左右括号在右,两个括号的方向也要和正常的括号方向一致。
思路
一个栈,循环字符串里的括号,要是能和栈顶的括号匹配上,那就把栈顶的括号弹出去,要是匹配不上,那就压进去,循环结束后看栈是否为空,如果是空那就是有效的括号。
代码
class Solution {
public:
stack<char> st;
bool isValid(string s) {
for (int i = 0; i < s.size(); i++) {
if (st.empty()) {
st.push(s[i++]);
}
if (st.top() == '(' && s[i] == ')' || st.top() == '{' && s[i] == '}' || st.top() == '[' && s[i] ==']') {
st.pop();
}
else st.push(s[i]);
}
if (st.empty()) {
return true;
}
return false;
}
};
删除字符串中的所有相邻重复项
和上面的思路一样的
注意一下最后要输出一个字符串,就需要把栈里的数pushback到字符串中,还需要reverse一下字符串
代码
class Solution {
public:
string removeDuplicates(string s) {
stack<char> st;
string result;
for (int i = 0; i < s.size(); i++) {
if (st.empty() || st.top() != s[i]) {
st.push(s[i]);
}
else {
st.pop();
}
}
while(!st.empty()) {
result.push_back(st.top());
st.pop();
}
reverse(result.begin(), result.end());
return result;
}
};
逆波兰表达式
思路
一个栈,不是操作符就压入栈,是操作符的部分再根据操作符的种类去计算,计算结果再亚入栈中要定义两个变量放两个操作数,注意他们的顺序,他们是从栈里取出来的,第二个其实是第一个。还要注意类型是字符还是字符串
代码
class Solution {
public:
stack<int> st;
int evalRPN(vector<string>& tokens) {
for (int i = 0; i < tokens.size(); i++) {
if (tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/") {
int num2 = st.top();
st.pop();
int num1 = st.top();
st.pop();
if (tokens[i] == "+") st.push(num1 + num2);
if (tokens[i] == "-") st.push(num1 - num2);
if (tokens[i] == "*") st.push(num1 * num2);
if (tokens[i] == "/") st.push(num1 / num2);
}
else {
st.push(stoi(tokens[i]));
}
}
return st.top();
}
};