栈与队列算法题
栈与队列
颠倒一个栈的元素顺序
问题:假设有一个栈{1,2,3,4,5,6},6是栈顶,1是栈底,现在要把这个栈中的元素颠倒一下。
思路:最简单的办法当然是把栈中的元素依次pop到一个数组中,然后把这个数组再push回栈里面即可,但这样需要O(n)的辅助空间。
下面介绍一种仅使用O(1)辅助空间的算法,我们知道,可以使用递归来模拟栈的操作。我们借助函数递归pop元素,这样在递归的函数栈上依次有
{6,5,4,3,2,1},1是栈顶,6是栈底,然后在递归返回的时候,如何把当前元素塞到原栈的底部呢?这里借助了另一个递归!
C++代码实现如下:
void Add2Bottom(stack<int> &s, int val) { int top; if (s.empty()) { s.push(val); } else { top = s.top(); s.pop(); Add2Bottom(s, val); s.push(top); } } void Reverse(stack<int> &s) { int top; if (!s.empty()) { top = s.top(); s.pop(); Reverse(s); Add2Bottom(s, top); } } int main() { int n; int array[6] = {1,2,3,4,5,6}; stack<int> s; for (n=0; n<6; n++) s.push(array[n]); Reverse(s); while (!s.empty()) { cout<<s.top()<<endl; s.pop(); } }
栈的sort函数
递归实现
template<class T> void push(stack<T> &s, T val) { if (s.empty() || val <= s.top()) { s.push(val); return; } T min = s.top(); s.pop(); push(s, val); s.push(min); } template<class T> void stackSort(stack<T> &s) { stack<T> s2; while (!s.empty()) { push(s2, s.top()); s.pop(); } s.swap(s2); }
括号匹配
问题:判断一个文本中,括号是否匹配?
思路:从头到尾扫描字符串,每次遇到左括号(如'(', '[', '{')就压入堆栈,如果遇到右括号(如')', ']', '}')就与栈顶元素比较,如果成对,OK,否则判断不匹配。
代码如下:
#include <iostream> #include <stack> #include <set> #include <string> using namespace std; /* * vaild return true, else return false */ bool judge_bracket(const string & str) { stack<char> st; set<char> left; set<char> right; left.insert('('); left.insert('['); left.insert('{'); right.insert(')'); right.insert(']'); right.insert('}'); for (int i=0; i!=str.size(); i++) { set<char>::iterator it1 = left.find(str[i]); set<char>::iterator it2 = right.find(str[i]); if (it1 != left.end()) { // match left st.push(str[i]); } else if (it2 != right.end()) { // match right if (st.size() == 0 ) return false; // stack is empty if (str[i] - st.top() <= 2 ) { // 右括号的ASCII码比其成对的左括号大1或2 st.pop(); } else { cout << "str[i]=" << str[i] << "top=" << st.top() <<endl; return false; } } } return true; } int main(int argc, char* argv[]) { string test_buffer[5] = {"]({[", "({[]})","([)]{}","(()[{}])","{[((()))]([])}"}; //test for (int i=0; i<5; i++) { cout << "The string is \"" << test_buffer[i] << "\", The result is " << (judge_bracket(test_buffer[i]) ? "matched" : "not matched" ) << endl; } return 0; }
栈的min函数
定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。要求函数min、push以及pop的时间复杂度都是O(1)。
思路:利用辅助栈,每次对stack push/pop一个元素时,同时也要更新辅助栈(存储最小元素),例如:
步骤 数据栈 辅助栈
1.push 3 3 3
2.push 4 3,4 3,3
3.push 2 3,4,2 3,3,2
4.push 1 3,4,2,1 3,3,2,1
5.pop 3,4,2 3,3,2
6.pop 3,4 3,3
7.push 0 3,4,0 3,3,2
C++代码实现:
class MinStack { public: /** initialize your data structure here. */ MinStack() { minIndex.push(INT_MAX); } void push(int x) { if (x < minIndex.top()) { minIndex.push(x); } else { minIndex.push(minIndex.top()); } data.push(x); } void pop() { minIndex.pop(); data.pop(); } int top() { if (data.empty()) return INT_MAX; return data.top(); } int getMin() { return minIndex.top(); } private: stack<int> data; stack<int> minIndex; };
栈的max函数
定义栈的数据结构,要求添加一个max函数,能够得到栈的最大元素。要求函数max、push以及pop的时间复杂度都是O(1)。
这个与栈的min函数实现类似
class MaxStack { public: MaxStack() { maxIndex.push(INT_MIN); } void Push(int x) { maxIndex.push(std::max(x, maxIndex.top())); data.push(x); } int Pop() { if (data.empty()) return INT_MIN; maxIndex.pop(); int res = data.top(); data.pop(); return res; } int Top() { if (data.empty()) return INT_MAX; return data.top(); } int Max() { return maxIndex.top(); } bool Empty() { return data.empty(); } private: stack<int> data; stack<int> maxIndex; };
栈的push、pop序列
输入两个整数序列,其中一个序列表示栈的push顺序,判断另一个序列有没有可能是对应的pop顺序。为了简单起见,我们假设push序列的任意两个整数都是不相等的。
比如输入的push序列是1、2、3、4、5,那么4、5、3、2、1就有可能是一个pop系列。因为可以有如下的push和pop序列:push 1,push 2,push 3,push 4,pop,push 5,pop,pop,pop,pop,这样得到的pop序列就是4、5、3、2、1。但序列4、3、5、1、2就不可能是push序列1、2、3、4、5的pop序列。
C++实现:
int verify(int in[], int out[], int N) { int n; int m = 0; stack<int> s; for (n=0; n<N; n++) { s.push(in[n]); while (!s.empty()) { if (s.top() == out[m]) { s.pop(); m++; } else { break; } } } return s.empty(); } int main() { int ret; int in[5] = {1,2,3,4,5}; int out[5] = {4,3,5,1,2}; ret = verify(in, out, 5); cout<<"ret="<< ret<<endl; }
用栈实现队列
设2 个栈为A和B,A用作入队,B用作出队。
队满:A满且B不为空;
队空:A和B都为空;
入队:
(1) 如果A未满,将新元素push 入栈A;
(2) 如果A已满,将栈A中所有元素依次pop 出并push 到栈B,然后将元素入栈A;
出队:
(1) 如果B为空,则将栈A 中所有元素依次pop 出并push 到栈B,然后将元素出栈B;
(2) 如果B不为空,将栈B 的栈顶元素pop 出;
C++代码实现:
bool queue_empty(stack<int> &s1, stack<int> &s2) { return s1.empty() && s2.empty(); } void enqueue(stack<int> &s1, stack<int> &s2, int val) { s1.push(val); } void dequeue(stack<int> &s1, stack<int> &s2, int &val) { int top; if (s2.empty()) { while (!s1.empty()) { top = s1.top(); s1.pop(); s2.push(top); } } if (!s2.empty()) { val = s2.top(); s2.pop(); } else { cout<<"error: queue is empty"<<endl; } } int main() { int n; int array[6] = {1,2,3,4,5,6}; stack<int> s1; stack<int> s2; for (n=0; n<6; n++) enqueue(s1, s2, array[n]); while (!queue_empty(s1, s2)) { dequeue(s1, s2, n); cout<<n<<endl; } }
注意:这里没有考虑栈空间可能满的问题。
其实,也可以用一个栈来模拟队列结构,仍然是借助递归栈,每次往栈插入元素时,把它塞到栈底,这样就实现了FIFO的队列结构。
代码如下:
void enqueue2(stack<int> &s, int val) { int top; if (s.empty()) { s.push(val); } else { top = s.top(); s.pop(); enqueue2(s, val); s.push(top); } } int main() { int n; int array[6] = {1,2,3,4,5,6}; stack<int> s; for (n=0; n<6; n++) enqueue2(s, array[n]); while (!s.empty()) { n = s.top(); s.pop(); cout<<n<<endl; } }
用队列实现栈
设2 个队列为A和B,A用作入队/出队,B用作辅助。
队满:A满且B不为空;
队空:A和B都为空;
入栈:将新元素插入队列A;
出栈:
(1) 除最后一个元素外,将队列A的元素全部插入到队列B;
(2) 将队列A的最后一个元素出队;
(3) 将队列B的元素换回到队列A;
void stack_pop(queue<int> &q1, queue<int> &q2, int &n) { int i, head; while (!q1.empty()) { head = q1.front(); q1.pop(); if (q1.empty()) { n = head; } else { q2.push(head); } } while (!q2.empty()) { head = q2.front(); q1.push(head); q2.pop(); } } int main() { int n; int array[6] = {1,2,3,4,5,6}; queue<int> q1, q2; for (n=0; n<6; n++) q1.push(array[n]); while (!q1.empty()) { stack_pop(q1, q2, n); cout<<n<<endl; } }
队列的Max函数
前面提到可以用两个栈实现队列,以及栈的Max函数实现,把这两个组合一下就能实现队列的Max函数,如下
class MaxQueue { public: void EnQueue(int v) { stk2.Push(v); } int DeQueue() { if (stk1.Empty()) { while (!stk2.Empty()) { stk1.Push(stk2.Pop()); } } return stk1.Pop(); } int Max() { return max(stk1.Max(), stk2.Max()); } bool Empty() { return stk1.Empty() && stk2.Empty(); } private: MaxStack stk1; MaxStack stk2; };