栈与队列part01(二)
栈与队列以底层容器完成所有的工作,对外提供统一接口,且底层容器是可插拔的
1. 用栈实现队列
// 用两个栈实现队列// in入栈// out出栈 实现FIFOstack<int> stin;stack<int> stout;MyQueue() {}void push(int x) {stin.push(x);}int pop() {// 将元素放入out准备出栈if (stout.empty()) {while (!stin.empty()) {int a = stin.top();stin.pop();stout.push(a);} } int b = stout.top();stout.pop();return b;}int peek() {// if (!stout.empty()) return stout.top();while (!stin.empty()) {int a = stin.top();stin.pop();stout.push(a);}return stout.top();}bool empty() {if (stin.empty() && stout.empty()) return true;return false;}
2. 用队列实现栈
可以用两个队列实现栈,也可以通过改变队列中元素的排列用一个队列实现栈来提高空间利用,以下是用一个队列实现栈的方法
// 使用一个队列实现栈需要记录队列中元素的数量// 以此知道栈顶元素的位置int count = 0;queue<int> q;MyStack() {}// 用一个队列实现栈void push(int x) { q.push(x);count++;}int pop() {// 队列不为空if (count > 0) {int a = count-1;while (a--) {int b = q.front();q.pop();q.push(b);}}int res = q.front();q.pop();count--;return res;}int top() {// 直接调用pop()获取栈顶元素,记得还要将元素入栈,元素数量+1int res = this->pop();q.push(res);count++;return res;}bool empty() {if (count == 0) return true;return false;}
3. 有效的括号
这是一个对栈的应用:
1. 遍历字符串遇到左括号就将对应右括号放入栈中,遇到匹配的右括号就将栈顶元素出栈,如果遍历完字符串刚好栈为空,说明是有效字符串
2.如果在遍历的过程中发现下一个右括号和栈顶括号不匹配说明括号闭合失败,不是有效字符串
3. 如果在遍历过程中发现栈是空的,说明前面有单独的右括号,也不是有效字符串
// 由题意得字符数量一定是偶数if (s.size() % 2 != 0 ) return false;stack<char> st;for (int i = 0; i < s.size(); i++) {if (s[i] == '(') st.push(')');else if (s[i] == '[') st.push(']');else if (s[i] == '{') st.push('}');// 如果没有左括号或者括号不能闭口(与栈顶元素不相同)不是有效字符串else if (st.empty() || st.top() != s[i]) return false;// else st.pop();}if (st.empty()) return true;return false;
4. 删除字符串中所有相邻重复项
本题也是对栈的应用:
遍历字符串将元素依次入栈,如果当前元素和栈顶元素执行出栈操作,且元素不入栈相当于完成了删除操作,最后栈内的元素就是答案
string removeDuplicates(string s) {if (s.size() == 1) return s;else if(s.size() == 2) {if (s[0] == s[1]) return "";return s;}stack<char> st;// 执行删除操作for (int i = 0; i < s.size(); i++) {if (!st.empty() && st.top() == s[i]) {st.pop();continue;}st.push(s[i]);}// 收集结果string res;while(!st.empty()) {char a = st.top();st.pop();res+=a;}// 需要按照原字符串顺序输出reverse(res.begin(), res.end());return res;}