栈和队列的经典面试题(一)
来源:互联网 发布:java io读取文件 编辑:程序博客网 时间:2024/06/05 10:32
一、实现一个栈,要求实现Push(入栈)、Pop(出栈)、Min(返回最小值的操作)的时间复杂度为O(1)。
分析:
思路1:利用两个栈,第二个栈的栈顶只放当前原生栈的最小值,Pop和Push时两个栈都进行,Min时只有第二个栈返回其栈顶值。
eg1——以入栈 5 3 6 7 8 0 为例,其入栈、求最小值、出栈的过程如下图:
此思路在本例题下可行,但如果换个例子,要求入栈 5 3 6 3 3 0 的话就会出状况,这个时候,需要进行改进。
改进1:如果原生栈中的元素不重复时,第二个栈中不出现重复数字;若原生栈中的元素出现重复时,第二个栈中同样引入该重复数字。Push时第二个栈只压入截至目前的最小值和原生栈中重复的数,Pop时第二个栈只在等于原生栈中值时才出,Min时只有第二个栈返回其栈顶值。其入栈、求最小值、出栈的过程如下图:
但这时仍然存在问题,即当原生栈需要压入的数据有大量重复的时候,思路二的方法的效率就会显得很低。这时仍需要进行改进。
改进2:使用引用计数,对第二个栈中的每个数配一个引用计数,当引用计数为0时再Pop。此方法为最优方法。
实现:
思路1实现:
#include <iostream>#include <stack>using namespace std;template <class T>class MinStack{public: void Push(const T& x) { _st.push(x); if ((_minst.empty()) || (x < _minst.top())) { _minst.push(x); //minst为空时直接压栈,不为空时需要判断是否为当前最小值 } else { _minst.push(_minst.top()); //保持压入最小值 } } void Pop() { _st.pop(); _minst.pop(); } void Min() { /*return _minst.top();*/ cout << "min= " << _minst.top() << endl; } void Print() { while (!_st.empty()) { cout << _st.top() << " "; _st.pop(); } cout << endl; }protected: stack<T> _st; stack<T> _minst;};int main(){ MinStack<int> s; s.Push(3); s.Push(2); s.Push(6); s.Push(5); s.Push(1); s.Push(7); /*s.Min(); s.Print();*/ s.Pop(); s.Pop(); s.Min(); s.Print(); system("pause"); return 0;}
改进1实现(只需更改Push和Pop):
void Push(const T& x) { _st.push(x); if ((_minst.empty()) || (x <= _minst.top())) { _minst.push(x); //minst为空时直接压栈,不为空时需要判断是否为最小值或重复值 } } void Pop() { if (_st.top() == _minst.top()) { _minst.pop(); } _st.pop(); }
改进2的实现:
template <class T>class MinStack{public: struct ValueRef //定义一个内部类作第二个栈 { T _value; size_t _ref; //计数 ValueRef() //构造 初始化_ref :_ref(0) {} };protected: stack<T> _st; stack<ValueRef> _minst;};
添加内部类,其他运算据此进行。
二、使用两个栈实现一个队列。
分析:
有两个栈s1和s2,s1负责入队,压栈即可。出队时,若s2为空,将s1中元素导入s2中,若s2不为空,由s2出栈来完成出队。
实现:
#include <iostream>#include <stack>using namespace std;template <typename T>class CQueue{public: CQueue(void) {} ~CQueue(void) {} void appendTail(const T& node); T deleteHead();private: stack<T> stack1; stack<T> stack2;};template<class T>void CQueue<T>::appendTail(const T& node)//在队列尾部添加数据{ stack1.push(node);}template<class T>T CQueue<T>::deleteHead(){ T tmp = 0; if (stack2.empty()) //若栈2为空 { while (!stack1.empty()) { tmp = stack1.top(); stack2.push(tmp); stack1.pop(); } } tmp = stack2.top(); stack2.pop(); return tmp;}void Test(){ CQueue<int> q1; q1.appendTail(1); q1.appendTail(2); q1.appendTail(3); q1.appendTail(4); q1.deleteHead(); q1.appendTail(5); q1.appendTail(6); q1.appendTail(7);}int main(){ Test(); system("pause"); return 0;}
三、使用两个队列实现一个栈
分析:
进栈:把元素push进非空的队列,如果两者都是空的,则随意。
出栈:把非空队列里面的前n-1个元素push到空队列里面,再把最后一个元素拿出来即可。
循环以上步骤,即可得到实现目的。
实现:
#include "queue"#include "iostream"using namespace std;template <typename T>class Stack {public: Stack() { count = 0; } ~Stack() {} void push(const T & data) { if (!q2.empty()) { q2.push(data); } else { q1.push(data); } count++; } T pop() { T temp; if (!q1.empty()) { for (int i = 0; i < count - 1; ++i) { q2.push(q1.front()); q1.pop(); } temp = q1.front(); q1.pop(); count--; return temp; } else if (!q2.empty()) { for (int i = 0; i < count - 1; ++i) { q1.push(q2.front()); q2.pop(); } temp = q2.front(); q2.pop(); count--; return temp; } } T top() { T temp; if (!q1.empty()) { for (int i = 0; i < count - 1; ++i) { q2.push(q1.front()); q1.pop(); } temp = q1.front(); q2.push(temp); q1.pop(); return temp; } else if (!q2.empty()) { for (int i = 0; i < count - 1; ++i) { q1.push(q2.front()); q2.pop(); } temp = q2.front(); q1.push(temp); q2.pop(); return temp; } } int size() const { return count; } bool empty() { return count == 0; }private: queue<T> q1; queue<T> q2; int count;};template <typename T> //注意非模板类的成员函数的模板姿势int print(Stack<T> s) { while (!s.empty()) { cout << s.pop() << " "; } cout << endl;}
阅读全文
0 0
- 栈和队列的经典面试题(一)
- 栈和队列面试题(一)
- 经典面试题一:用两个栈实现一个队列
- 经典的SQL面试题(一)
- 【面试题】栈和队列的面试题
- 队列和栈的面试题
- 栈和队列的常见面试题
- 栈和队列的面试题
- 栈和队列的相关面试题
- 栈和队列的相关面试题
- @经典面试题(一)@
- 经典面试题(一)
- 两个栈实现队列(经典面试题)java
- 栈和队列面试题(二)
- 栈和队列面试题(三)
- 栈和队列面试题(四)
- 栈和队列面试题
- 栈和队列面试题
- sharedperferences 记住密码,自动登录demo
- JVM结构
- const变量通过指针修改 详解
- VIVADO布线布不通过描述
- 如何在谷歌浏览器查看axure文件
- 栈和队列的经典面试题(一)
- 常见框架中的单例、多例与线程安全性总结
- 22. Generate Parentheses
- DTD--eclipse中设置XML文件自动补全的方法步骤
- js自适应rem -- 主要适用于移动端
- 第一篇博客
- spring集成webservice框架cxf,访问报错service not found
- clippingNode新手引导
- javascript获取地址栏各字段方法