<剑指offer>之栈和队列所有题目

【引言】stack和queue的题目不太多,而且几道题目大概思路要么是构造辅助stack或者queue,要么是根据stack的FILO和queue的FIFO特性下手有一定的技巧性

【题目7】用两个队列实现栈

用两个栈实现队列。队列声明如下,请实现它的两个函数append_tail和delete_head在队列的队尾添加数据和删除队头
[cpp]  view plain copy
  1. <span style="background-color: rgb(255, 255, 255);">template<typename T>  
  2. class Queue_by_stack  
  3. {  
  4. public:  
  5.     Queue_by_stack(){};  
  6.     ~Queue_by_stack(){};  
  7.   
  8.     void append_tail(const T& node);  
  9.     T delete_head();  
  10. protected:  
  11. private:  
  12.     stack<T> stack1;  
  13.     stack<T> stack2;  
  14. };</span>  

分析: 队列的特性是先进后出,比如对于1,2,3,4序列来说,首先将序列压入栈(stack1和stack2随便选一个),要实现delete_head的话,不能对stack1进行pop,因为这时stack1的top值是4,我们要删除的是1,注意这时候stack2还没有利用,如果我将stack1里的数据都逐个pop,push进去stack2,对于stack2;来说,那不就正好相当于原序列吗?实现delete_head的话只需对stack2进行pop就行了,append_tail的话只需往空的stack1里面push就行了。代码实现如下
【代码】
[cpp]  view plain copy
  1. <span style="background-color: rgb(255, 255, 255);">#include <iostream>  
  2. #include <stack>  
  3. using namespace std;  
  4.   
  5. template<typename T>  
  6. class Queue_by_stack  
  7. {  
  8. public:  
  9.     Queue_by_stack(){};  
  10.     ~Queue_by_stack(){};  
  11.   
  12.     void append_tail(const T& node);  
  13.     T delete_head();  
  14. protected:  
  15. private:  
  16.     stack<T> stack1;  
  17.     stack<T> stack2;  
  18. };  
  19.   
  20.   
  21. template<typename T>  
  22. T Queue_by_stack<T>::delete_head()  
  23. {  
  24.     T tmp;  
  25.     if (stack2.empty())  
  26.     {  
  27.         while (!stack1.empty())  
  28.         {  
  29.             tmp = stack1.top();  
  30.             stack2.push(tmp);  
  31.             stack1.pop();  
  32.         }  
  33.     }  
  34.     if (stack2.empty())  
  35.     {  
  36.         return -1;  
  37.     }  
  38.     tmp = stack2.top();  
  39.     stack2.pop();  
  40.     return tmp;       
  41. }  
  42.   
  43. template<typename T>  
  44. void Queue_by_stack<T>::append_tail( const T& node )  
  45. {  
  46.     stack1.push(node);  
  47. }</span>  
【测试】
[cpp]  view plain copy
  1. <span style="background-color: rgb(255, 255, 255);">int main()  
  2. {  
  3. #if 0  
  4.     Queue_by_stack<char> my_queue;  
  5.     my_queue.append_tail('a');  
  6.     my_queue.append_tail('b');  
  7.     my_queue.append_tail('c');  
  8.   
  9.     my_queue.delete_head();  
  10.     my_queue.delete_head();  
  11.     my_queue.delete_head();  
  12.     my_queue.delete_head();  
  13.     my_queue.append_tail('d');  
  14.     my_queue.append_tail('e');  
  15.     my_queue.delete_head();  
  16. #endif  
  17. }</span>  

【扩展】使用两个队列实现一个栈

这个栈的声明如下:
[cpp]  view plain copy
  1. template<typename T>  
  2. class Stack_by_queue  
  3. {  
  4. public:  
  5.     Stack_by_queue(){};  
  6.     ~Stack_by_queue(){};  
  7.   
  8.     void append_tail(const T& node);  
  9.     T delete_head();  
  10. protected:  
  11. private:  
  12.     queue<T> queue1;  
  13.     queue<T> queue2;  
  14. };  


分析:栈的特性是先进后出,举一个序列1,2,3,4来说,我们试着往一个queue1里面push进去,这时候queue1的队头是1,队尾是4,这时候要实现delete_head的话,对应的栈应该删除4,对于queue1的队尾,前面的1,2,3,都是不需要的。
实现dalete_head解决方法就是,依次弹出1,2,3并且压入queue2中,queue1里面只保存4,这时候要delete_head的话,对queue1进行pop操作就行了,然后queue1为空(注意这个状态),然后我要继续delete_head,这个时候也是按照上面的思路,将queue2的1,2依次弹出,压入queue1里面,知道剩下最后一个队尾元素3,将它pop掉就行了!这时候的状态是queue1不为空,queue2为空。
实现append_tail的话也容易。注意上面的删除头以后的两种状态其实可以可以归结为一种,那就是其中一个queue为空,另一个可以为空(这个时候模拟的stack就是空),或者不为空,append_tail来说,只需往非空的queue里面添到队尾就行了,若是都为空,随便选一个即可
【实现】
[cpp]  view plain copy
  1. #include <queue>  
  2. using namespace std;  
  3. template<typename T>  
  4. class Stack_by_queue  
  5. {  
  6. public:  
  7.     Stack_by_queue(){};  
  8.     ~Stack_by_queue(){};  
  9.   
  10.     void append_tail(const T& node);  
  11.     T delete_head();  
  12. protected:  
  13. private:  
  14.     queue<T> queue1;  
  15.     queue<T> queue2;  
  16. };  
  17.   
  18. //保证在所有的过程中,至少队列有一个是空的  
  19. template<typename T>  
  20. T Stack_by_queue<T>::delete_head()  
  21. {  
  22.     T tmp;  
  23.     if(queue1.empty() && !queue2.empty())  
  24.     {  
  25.         //2->1  
  26.           
  27.         if (queue2.size() < 1)  
  28.         {  
  29.             return -1;  
  30.         }  
  31.         while(queue2.size() != 1)  
  32.         {  
  33.             tmp = queue2.front();  
  34.             queue2.pop();  
  35.             queue1.push(tmp);  
  36.         }  
  37.         tmp = queue2.front();  
  38.         queue2.pop();  
  39.         return tmp;  
  40.     }  
  41.     if (!queue1.empty() && queue2.empty())  
  42.     {  
  43.         //1->2  
  44.         T tmp;  
  45.         if (queue1.size() < 1)  
  46.         {  
  47.             return -1;  
  48.         }  
  49.         while(queue1.size() != 1)  
  50.         {  
  51.             tmp = queue1.front();  
  52.             queue1.pop();  
  53.             queue2.push(tmp);  
  54.         }  
  55.         tmp = queue1.front();  
  56.         queue1.pop();  
  57.         return tmp;  
  58.   
  59.     }  
  60.     else  
  61.         return -1;    
  62. }  
  63.   
  64. template<typename T>  
  65. void Stack_by_queue<T>::append_tail( const T& node )  
  66. {  
  67.     //保证有一队列为空,若全为空,则队空,任选一个队列就行  
  68.     if (queue1.empty() && !queue2.empty())  
  69.         queue2.push(node);  
  70.     if (!queue1.empty() && queue2.empty())  
  71.         queue1.push(node);  
  72.     if (queue1.empty() && queue2.empty())  
  73.         queue1.push(node);  
  74.     else   
  75.         return;  
  76. }  

【测试】
[cpp]  view plain copy
  1. int main()  
  2. {  
  3. #if 1  
  4.   
  5.   
  6.     Stack_by_queue<char> my_stack;  
  7.     my_stack.append_tail('a');  
  8.     my_stack.append_tail('b');  
  9.     my_stack.append_tail('c');  
  10.     my_stack.delete_head();  
  11.     my_stack.delete_head();  
  12.     my_stack.delete_head();  
  13.     my_stack.delete_head();  
  14.     my_stack.append_tail('d');  
  15.     my_stack.append_tail('e');  
  16.     my_stack.delete_head();  
  17.     my_stack.append_tail('f');  
  18. #endif  
  19. }  

【题目21】包含min函数的栈

描述:定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的函数。在该栈中,调用min,push,pop的时间复杂度都是O(1)
思路:首先是一个栈,这个栈已经是最常见的那种,我们需要改造它使它能够在O(1)时间内返回最小元素,刚开始的思路是往栈里面添加一个元素放在stack的顶部,表示当前栈里面的最小元素,如果压入的元素比它小,那么更新它,并且将它pop出来,放在一个临时值里面,将刚才要压入的序列元素push进去栈,再将最小值压进去,看上去可行。 但这样有问题,比如说我对栈pop操作,我需要将栈顶的最小元素弹出,存起来,然后将真正的栈顶元素弹出,这个时候我要是再把刚才保存的栈顶元素压入原栈,就不一定对了,因为删除一个元素以后,最小元素也要更新,如何得到次小元素的值呢?明显我们需要保存次小,再次小。。。的值,为此我们使用两个栈,一个是普通的数据栈,data_stack,和另外一个auxi_stack辅助栈,首先在空的时候都压入两个栈,然后对于压入的序列,比较这个元素和辅助栈栈顶元素,如果小于这个栈顶那么在压入数据栈的时候也压入辅助站,否则,将辅助栈的顶部元素再次压入一次,这样保证了两个栈的大小相等,这样才能在pop的时候同步,否则我在调用min以后更新候判断就比较麻烦。
这样需要的空间就是两个相等的栈
【代码】
[cpp]  view plain copy
  1. template <typename T>  
  2. class  min_stack  
  3. {  
  4. public:  
  5.     min_stack(){};  
  6.     ~min_stack(){};  
  7.   
  8.     T my_min();  
  9.     void my_push(const T& data);  
  10.     void my_pop();  
  11. protected:  
  12. private:  
  13.     stack<T> data_stack;  
  14.     stack<T> auxi_stack;  
  15. };  
  16.   
  17. template <typename T>  
  18. void min_stack<T>::my_pop()  
  19. {  
  20.     if (auxi_stack.empty() && data_stack.empty())  
  21.         return;  
  22.     else  
  23.     {  
  24.         auxi_stack.pop();  
  25.         data_stack.pop();  
  26.     }  
  27. }  
  28.   
  29. template <typename T>  
  30. void min_stack<T>::my_push(const T& data)  
  31. {  
  32.     data_stack.push(data);  
  33.     if(auxi_stack.empty() || data < auxi_stack.top())  
  34.         auxi_stack.push(data);  
  35.     else  
  36.         auxi_stack.push(auxi_stack.top());  
  37.   
  38. }  
  39.   
  40. template <typename T>  
  41. T min_stack<T>::my_min()  
  42. {  
  43.     if(!auxi_stack.empty())  
  44.         return auxi_stack.top();  
  45.     else  
  46.         return -1;  
  47. }  
测试】
[cpp]  view plain copy
  1. int main()  
  2. {  
  3.     min_stack<int> my_min_stack;  
  4.     my_min_stack.my_push(3);  
  5.     my_min_stack.my_push(2);  
  6.     my_min_stack.my_push(1);  
  7.     my_min_stack.my_push(8);  
  8.     my_min_stack.my_min();  
  9.     my_min_stack.my_pop();  
  10.     my_min_stack.my_min();  
  11.     my_min_stack.my_push(2);  
  12.     my_min_stack.my_push(1);  
  13.     my_min_stack.my_min();  
  14.   
  15.   
  16. }  

【题目22】判断压入弹出顺序问题

题目描述:
对于两个序列,第一个表示栈的压入顺序,第二个序列表示栈的弹出顺序,判断下第二个序列是否是第一个序列的弹出顺序。假设原数序列元素都不相等。比如对于原始序列1,2,3,4,5来说,序列4,5,1,2,3就是它的一个弹出序列,对原始序列执行的操作时push,push,push,push,pop,push,pop,pop,pop,pop
思路:对于这种问题需要慢慢分析,对于4,5,1,2,3来说,要首先弹出一个4,必须将原始序列中4之前的元素都压栈,然后弹出4,然后看第二个元素5,首先栈顶不是这个5,我们需要在上次压栈改变后原始序列中找,只剩第五个元素5,压栈,弹出,第三个元素3,栈顶就是,弹出,依次这样。。。如果碰见在原始序列中找不到并且栈顶也不是这个元素的情况,无论如何也不能是原始序列,这个元素肯定在栈里面,非栈顶。so,代码如下。。

【代码】
[cpp]  view plain copy
  1. #include <stack>  
  2. using namespace std;  
  3.   
  4. //思路:遍历第二个序列,对于序列的每个元素,首先看这个元素在不在栈顶,在的话弹出;  
  5. //不在的话遍历第一个序列,一边遍历一边将第一个序列元素压栈,如果第一个序列没有,则证明则第二个序列的这个元素已经压进去栈了  
  6. bool is_pop_order(const int* to_push, const int* to_pop, int len)  
  7. {  
  8.     if(to_push== NULL || to_pop== NULL || len < 1)  
  9.         return false;  
  10.     stack<int> tmp_stack;   
  11.     int tmp;  
  12.     int i, j;  
  13.     for (i = 0, j = 0; i < len; i++)  
  14.     {  
  15.         tmp = to_pop[i];  
  16.         if (!tmp_stack.empty() && tmp == tmp_stack.top())  
  17.         {  
  18.             tmp_stack.pop();  
  19.         }  
  20.         else  
  21.         {  
  22.             while(j < len && tmp != to_push[j])  
  23.             {  
  24.                 tmp_stack.push(to_push[j]);  
  25.                 ++j;  
  26.             }  
  27.             if (j == len)//第一个序列里面没有,失败  
  28.             {  
  29.                 return false;  
  30.             }  
  31.             else//在第一个序列的j个位置  
  32.             {  
  33.                 ++j;  
  34.             }  
  35.         }  
  36.     }  
  37.     return true;  
  38. }  
【测试】
[cpp]  view plain copy
  1. int main()  
  2. {  
  3.   
  4.     int a[] = {1,2,3,4,5};  
  5.     int b[] = {4,5,3,2,1};  
  6.     int c[] = {4,3,5,1,2};  
  7.     int d[1] = {5};  
  8.     int e[1] = {5};  
  9.     bool res1 = is_pop_order(a, b, sizeof(a)/sizeof(a[0]));  
  10.     bool res2 = is_pop_order(a, c, sizeof(a)/sizeof(a[0]));  
  11.     bool res3 = is_pop_order(d,e,1);  
  12. }  

【扩展】记得微软3月份的时候

有过类似的题目,现在找出来。



待续。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值