关于队列和栈的几道面试题
2016-09-18 16:00
471 查看
今天来说几道简单的栈和队列相关的几道面试题:
所以,我们给出一种解决思路:就是你需要有两个栈,一个保存数据,一个辅助作为保存最小值情况的栈。,然后当我们进行push的时候,如果辅助最小值的栈也是空的,那么就push,不是空的时候和最小值栈的栈顶进行比较,如果比它小,再进行压栈,否则,就不用push。在pop的时候,这个时候我们需要和栈顶比较,如果pop的数值和栈顶是一样大的话,那么久吧保存数据的栈和最小值的栈的栈顶都进行pop。
![](https://img-blog.csdn.net/20160918151553757)
在这,我们应该清楚,两个数据结构的数据特性,一个是先进后出,一个是后进先出,所以,我们在这里可以这样分析:
当我们入队操作的时候,对第一个栈进行压栈,如果我们想要pop的时候,这个时候其实是要pop的是第一个栈的栈底元素,所以这个时候我们把第一个栈栈顶元素push进入第二个栈,然后pop,这样依次到第一个栈空。然后我们再pop第二个栈顶元素的top,这样就是实现了出队。
![](https://img-blog.csdn.net/20160918151507085)
![](https://img-blog.csdn.net/20160918163046277)
采用奇偶栈
采用中间向两头的栈
采用两边向中间的栈
![](https://img-blog.csdn.net/20160918174958281)
上面两种都会存在空间利用率较低的问题,比如有一个栈数据很多,一个栈数据非常小,这个时候第三种方案是最好一些的。
1 . 实现一个栈,要求实现Push(入栈)、Pop(出栈)、Min(返回最小值的操作)的时间复杂度为O (1 )
第一道题,我们需要分析,我想一般的思维肯定是想到,开辟一块空间,进行保存最小值,这种方法也是大家通常地一下就可以想到的。但是在这里会有一个问题,就是如果你的最小值在栈顶,当你pop了栈顶以后,下面的数据中最小的元素就会发生改变,这个时候你无法得到新的最小的元素了。所以,我们给出一种解决思路:就是你需要有两个栈,一个保存数据,一个辅助作为保存最小值情况的栈。,然后当我们进行push的时候,如果辅助最小值的栈也是空的,那么就push,不是空的时候和最小值栈的栈顶进行比较,如果比它小,再进行压栈,否则,就不用push。在pop的时候,这个时候我们需要和栈顶比较,如果pop的数值和栈顶是一样大的话,那么久吧保存数据的栈和最小值的栈的栈顶都进行pop。
#define _CRT_SECURE_NO_WARNINGS 1 #pragma once #include<iostream> #include<cstdlib> #include<cassert> #include<stack> #include<vector> using namespace std; template<typename T> class Stack { public: void push(const T& d); void pop(); T& min(); private: stack<T>DataStack; stack<T>MinStack; }; template<typename T> void Stack<T>::push(const T& d) { DataStack.push(d); if (MinStack.empty() || d <= MinStack.top()) { MinStack.push(d); } } template<typename T> void Stack<T>::pop() { assert(!DataStack.empty()); if (DataStack.top() == MinStack.top()) { DataStack.pop(); MinStack.pop(); } DataStack.pop(); } template<typename T> T& Stack<T>::min() { return MinStack.top(); }
2 . 使用两个栈实现一个队列
对于这个问题的分析,我们可以转换为两个栈之间的来回循环倒的一个问题。在这,我们应该清楚,两个数据结构的数据特性,一个是先进后出,一个是后进先出,所以,我们在这里可以这样分析:
当我们入队操作的时候,对第一个栈进行压栈,如果我们想要pop的时候,这个时候其实是要pop的是第一个栈的栈底元素,所以这个时候我们把第一个栈栈顶元素push进入第二个栈,然后pop,这样依次到第一个栈空。然后我们再pop第二个栈顶元素的top,这样就是实现了出队。
#pragma once #include<iostream> #include<cstdlib> #include<cassert> #include<stack> using namespace std; template<typename T> class Queue { public: void push(const T& d); void pop(); size_t size(); bool empty(); T& front(); T& back(); private: stack<T > s1; stack<T > s2; }; template<typename T> void Queue<T>::push(const T& d) { s1.push(d); } template<typename T> void Queue<T>::pop() { assert((!s1.empty() )||(! s2.empty())); if (s2.empty()) { while (!s1.empty()) { s2.push(s1.top()); s1.pop(); } } s2.pop(); } template<typename T> size_t Queue<T>::size() { return s1.size() + s2.size(); } template<typename T> bool Queue<T>::empty() { return s1.empty()&&s2.empty(); } template<typename T> T& Queue<T>::front() { assert((!s1.empty()) || (!s2.empty())); if (s2.empty()) { while (!s1.empty()) { s2.push(s1.top()); s1.pop(); } } return s2.top(); } template<typename T> T& Queue<T>::back() { assert((!s1.empty()) || (!s2.empty())); if (s1.empty()) { while (!s2.empty()) { s1.push(s2.top()); s2.pop(); } } return s1.top(); }
3 . 使用两个队列实现一个栈
这道题是利用两个队列实现一个栈,和上面的那道题的方法是类似的,依然是通过调转实现数据特性就好了。让数据在两个队列当中进行流动,首先我们要确保数据必须只在一个栈中,push的时候对有元素的栈进行push。然后当我们pop的时候我们把一个队列中除了队尾的元素都push进第二个队列,最后把队尾的元素pop出去就好了,这样就可以实现一个栈。#pragma once #include<iostream> #include<cstdlib> #include<cassert> #include<queue> using namespace std; template<typename T> class Stack { public: void push(const T & d); void pop(); size_t size(); bool empty(); T& top(); private: queue<T> q1; queue<T> q2; }; template<typename T> void Stack<T>::push(const T& d) { if (q2.empty()&&q2.empty()) { q1.push(d); } else if (!q1.empty()) { q2.push(d); } else q1.push(d); } template <typename T> void Stack<T>::pop() { assert(!q1.empty() || !q2.empty()); if (!q1.empty()) { while (q1.size()>1) { q2.push(q1.front()); q1.pop(); } q1.pop(); } else { while (q2.size()>1) { q1.push(q2.front()); q2.pop(); } q2.pop(); } } template <typename T> bool Stack<T>::empty() { return q1.empty() && q2.empty(); } template <typename T> size_t Stack<T>::size() { return q1.size() + q2.size(); } template <typename T> T& Stack<T>::top() { assert(!q1.empty() || !q2.empty()); if (!q1.empty()) { return q1.back(); } else { return q2.back(); } }
4 . 元素出栈、入栈顺序的合法性。如入栈的序列(1 , 2 , 3 , 4 , 5 ),出栈序列为(4 , 5 , 3 , 2 , 1 )
这道题的思路也很简单,就是你所给定的两个序列数组,一个入栈序列,一个出栈序列。入栈序列比如说是(1,2,3,4,5);出栈序列比如说是(4,5,3,2,1);我们就首先入栈序列第一个元素入栈,这个时候让一个指针指向出栈序列第一个元素,如果出入栈以后,栈顶元素和指针所指的元素相等,那么就让栈顶元素出栈,让指针++,最后判定栈是否为空就好了,如果为空,就说明是合法的,如果不为空,就不合法。//判断元素出栈、入栈顺序的合法性。 //如:入栈的序列(1,2,3,4,5) //出栈序列为(4,5,3,2,1),是合法序列 //入栈序列(1,2,3,4,5), //出栈序列为(1,5,3,2,4)是不合法序列 #pragma once #include<iostream> #include<cstdlib> #include<cassert> #include<stack> using namespace std; int j = 0; bool JudgeStackSeq(int *InArr, int *OutArr, size_t sz) { stack<int > s; int j = 0; int pos=0; for (size_t i = 0; i < sz; i++) { s.push(InArr[i]); while (!s.empty()&&s.top()==OutArr[j]) { s.pop(); j++; } } return s.empty(); }
5 . 一个数组实现两个栈
最后是一个数组实现两个栈这个问题,这个问题我们可以采用三种思路来实现:采用奇偶栈
采用中间向两头的栈
采用两边向中间的栈
上面两种都会存在空间利用率较低的问题,比如有一个栈数据很多,一个栈数据非常小,这个时候第三种方案是最好一些的。
#pragma once #include<iostream> #include<cassert> #include<cstdlib> using namespace std; template<typename T> class Stack { public: Stack() : _array(0) , _sz1(0) , _sz2(0) , _capacity(0) { } ~Stack() { if (_array != NULL) { delete[] _array; } } void push1(const T& d) { CheckCapacity(); _array[_sz1] = d; _sz1++; } void pop1() { assert(_sz1 > 0); _sz1--; } bool empty1() { return _sz1 == 0; } void push2(const T& d) { CheckCapacity(); _array[_sz2] = d; _sz2--; } void pop2() { assert(_sz2 < _capacity - 1); _sz2++; } bool empty2() { return _sz2 == _capacity - 1; } size_t size1() { return _sz1; } size_t size2() { return _capacity - 1 - _sz2; } T& top1() { assert(_sz1 > 0); return _array[_sz1 - 1]; } T& top2() { assert(_sz2 != 0 || _sz2 < _capacity - 1); return _array[_sz2 + 1]; } void CheckCapacity() { if (_sz1 ==_sz2) { size_t NewCapacity = 2 * _capacity+2 ; T* tmp = new T[NewCapacity]; for (size_t i = 0; i < _sz1; ++i) { tmp[i] = _array[i]; } size_t j(0); for (j = NewCapacity - 1; j<NewCapacity-1&&j>NewCapacity - _sz2; --j) { tmp[j] = _array[_capacity]; } _sz2 = NewCapacity - (_capacity - _sz2); _capacity = NewCapacity; _array = tmp; } } protected: T* _array; size_t _sz1; size_t _sz2; size_t _capacity; };