堆疊相關面試題(詳解)
阿新 • • 發佈:2019-02-03
1. 實現一個棧,要求實現Push(出棧)、Pop(入棧)、Min(返回最小值的操作)時間複雜度為O(1)。
分析:設計兩個棧,一個棧用來push 、pop操作,另一個棧用來儲存當前最小值Min。當push元素小於等於Min棧頂元素時,將其壓入Min棧頂,當pop元素等於Min棧頂元素時,兩個棧均要pop出棧頂元素。下圖為各種情況的優缺點分析。
class StackWithMin { public: StackWithMin() {} ~StackWithMin() {} void Push(const int& x) { s1.push(x); if(s2.empty() || x <= s2.top()) { s2.push(x); } } void Pop() { assert(s1.size()>0 && s2.size()>0); if(s1.top() == s2.top()) { s2.pop(); } s1.pop(); } int Min() { assert(s1.size()>0 && s2.size()>0); return s2.top(); } private: stack<int> s1; stack<int> s2; //用於儲存最下元素 };
2. 使用兩個棧實現一個佇列。
分析:一個棧用來push資料,一個棧用來pop資料。
圖解
實現
//使用兩個棧實現一個佇列。 class Queue { public: void push(int node) { stack1.push(node); } int pop() { if(stack2.empty()) { while(!stack1.empty()) { stack2.push(stack1.top()); stack1.pop(); } } int top = stack2.top(); stack2.pop(); return top; } private: stack<int> stack1; stack<int> stack2; };
3. 使用兩個佇列實現一個棧。
分析:使用兩個佇列不斷的倒換元素,實現一個棧。下面為圖解,以及程式碼的實現過程。
圖解
#include<iostream> #include<queue> using namespace std; template <class T> class QueueToStack { public: QueueToStack() {} ~QueueToStack() {} void Push(T x) { if(q1.size()>0)//若q1不為NULL時,在q1中插入 { q1.push(x); } else if(q2.size()>0)//若q2不為NULL時,在q1中插入 { q2.push(x); } else { q1.push(x);//兩者均為NULL時,插入到q1 } } void Pop() { if(q1.size()==0)//如果queue1為空 { while(q2.size()>1)//保證queue2中有一個元素,將其餘元素儲存到queue1中 { q1.push(q2.front()); q2.pop(); } q2.pop(); } else//如果queue2為空 { while(q1.size()>1)//保證queue2中有一個元素,將其餘元素儲存到queue1中 { q2.push(q1.front()); q1.pop(); } q1.pop(); } } T Top() { if(q1.size()==0)//如果queue1為空 { while(q2.size()>1)//保證queue2中有一個元素,將其餘元素儲存到queue1中 { q1.push(q2.front()); q2.pop(); } T& data=q2.front(); q1.push(q2.front()); q2.pop(); return data; } else//如果queue2為空 { while(q1.size()>1)//保證queue2中有一個元素,將其餘元素儲存到queue1中 { q2.push(q1.front()); q1.pop(); } T& data=q1.front(); q2.push(q1.front()); q1.pop(); return data; } } bool Empty() { return (q1.empty() && q2.empty()); } private: queue<T> q1; queue<T> q2; };
4. 元素出棧、入棧順序的合法性。如入棧的序列(1,2,3,4,5),出棧序列為(4,5,3,2,1)。
分析:藉助輔助棧,如果下一個彈出的數字剛好是棧頂數字,那麼直接彈出。如果下一個彈出的數字不在棧頂,把壓棧序列中還沒有入棧的數字壓人輔助棧,直到把下一個需要彈出的數字壓入棧頂為止。如果所有的數字都壓入了仍然沒有找到下一個彈出的數字,那麼該序列不可能是一個彈出序列。
class Solution {
public:
bool IsPopOrder(vector<int> pushV,vector<int> popV)
{
if(pushV.size() == 0 || popV.size() == 0)
{
return false;
}
if(pushV.size() != popV.size())
{
return false;
}
stack<int> s; //藉助輔助棧
int j=0;
for(int i=0; i<popV.size(); ++i)
{
s.push(pushV[i]);
//當棧頂元素和出棧序列元素相等時,出棧
while(j<popV.size() && s.top() == popV[j])
{
s.pop();
++j;
}
}
return s.empty();
}
};
5. 一個數組實現兩個棧。
分析:一個數組實現兩個棧,分別從資料開始,和陣列末端實現。當兩個指標相當時,進行擴容。擴容時,需要將原陣列的資料寫入新陣列。
#include <iostream>
#include<assert.h>
using namespace std;
template<class T>
class TwoStack
{
public:
//構造
TwoStack()
:_arr(NULL)
,_top1(0)
,_top2(0)
,_capacity(0)
{
CheckCapacity();
}
//析構
~TwoStack()
{
if(NULL != _arr) //_arr不為NULL時,釋放_arr
{
delete[] _arr;
}
}
//拷貝構造
TwoStack(const TwoStack<T>& ts)
:_arr(new T[ts._capacity-ts._top2+ts._top1])
,_top1(ts._top1)
,_top2(_top1)
,_capacity(ts._capacity-ts._top2+ts._top1)
{
//拷貝資料
for(size_t i=0; i<_top1; i++)
{
_arr[i] = ts._arr[i];
}
size_t j = ts._capacity-1;
for(size_t i=_capacity-1; i>_top2;i--,j--)
{
_arr[i] = ts._arr[j];
}
}
//複製運算子過載
TwoStack<T>& operator=(TwoStack<T> ts)
{
int * tmp = ts._arr;
_top1 = ts._top1;
_top2 = ts._top2;
_capacity = ts._capacity;
swap(_arr,tmp);
return *this;
}
//push 、pop、top、size、empty
void Push1(const int& x)
{
CheckCapacity();
_arr[_top1++] = x;
}
void Push2(const int& x)
{
CheckCapacity();
_arr[_top2--] = x;
}
void Pop1()
{
if(Size1() == 0)
{
return;
}
--_top1;
}
void Pop2()
{
if(Size2() == 0)
{
return;
}
--_top2;
}
int Top1()
{
assert(_top1 > 0);
return _arr[_top1-1];
}
int Top2()
{
assert(_top2 < _capacity-1);
return _arr[_top2+1];
}
size_t Size1()
{
return _top1;
}
size_t Size2()
{
return _capacity - _top2 - 1;
}
bool Empty1()
{
if(_top1 == 0)
{
return true;
}
return false;
}
bool Empty2()
{
if(_top2 == _capacity-1)
{
return true;
}
return false;
}
protected:
void CheckCapacity()
{
//1.開始時擴容 2._top1 == _top2時,擴容
if(NULL == _arr)//開始時,當陣列為NULL時,給_arr分配空間
{
_capacity += 2;
_arr = new int[_capacity];
_top2 = _capacity - 1;
return;
}
if(_top1 == _top2) //如果_top1==_top2時,應該進行擴容
{
size_t newcapacity = _capacity*2;
int* tmp = new int[newcapacity];
//拷貝資料
for(size_t i=0; i<_top1; ++i)
{
tmp[i] = _arr[i];
}
size_t j = newcapacity - 1;
for(size_t k=_capacity-1; k>_top2; --k)
{
tmp[j] = _arr[k];
--j;
}
_top2 = j;
_capacity = newcapacity;
_arr = tmp;
}
}
private:
T * _arr; //析構時,應銷燬陣列中的內容
size_t _top1; //top1、top2分別表示棧的下標
size_t _top2;
size_t _capacity;
};