栈&&队列面试题

59 篇文章 8 订阅
42 篇文章 0 订阅
问题:
1. 实现一个栈,要求实现Push(出栈)、Pop(入栈)、Min(返回最小值的操作)的时间复杂度为O(1)
2. 使用两个栈实现一个队列
3. 使用两个队列实现一个栈
4. 判断元素出栈、入栈顺序的合法性。如:入栈的序列(1, 2, 3, 4, 5),出栈序列为(4, 5, 3, 2, 1)是合法序列,入栈的序列(1, 2, 3, 4, 5),出栈序列为(1, 5, 3, 2, 4)是不合法序列
5. 一个数组实现两个栈


1、 因为栈的特点就是“先进后出,后进先出”,而且只能在栈顶进行操作,所以Push和Pop的时间复杂度就是O(1),要返回最小值的话,可以用一个数组(或栈)记录栈中前n项的最小值,以空间换时间,这样的话就能在O(1)内返回最小值了。

例:



template<typename T>
class Stack
{
public:
       Stack()
              :_ptr(NULL)
              , _min(NULL)
              , _size(0)
              , _capacity(0){}
       ~Stack()
       {
              delete[] _ptr;
              delete[] _min;
              _ptr = NULL;
       }
       void Push(const T& data);
       void Pop();
       T& Top();
       bool Empty();
       size_t Size();
       T Min();
       void CheckCapacity();
protected:
       T* _ptr;
       T* _min;
       int _size;
       int _capacity;
};
template<typename T>
T& Stack<T>::Top()
{
       assert(_size>=0);
       return _ptr[_size - 1];
}
template<typename T>
bool Stack<T>::Empty()
{
       if (_size == 0)
              return true;
       else
              return false;
}
template<typename T>
size_t Stack<T>::Size()
{
       return (size_t)_size;
}
template<typename T>
void Stack<T>::Push(const T& data)
{
       CheckCapacity();
       _ptr[_size] = data;
       if (_size == 0)
       {
              _min[_size] = data;
       }
       else
       {
              if (data< _min[_size - 1])
              {
                     _min[_size] =data;
              }
              else
              {
                     _min[_size] =_min[_size-1];
              }
       }
       _size += 1;
}
template<typename T>
void Stack<T>::Pop()
{
       assert(_size >= 0);
       --_size;
}
template<typename T>
T Stack<T>::Min()
{
       assert(_size>=0);
       return _min[_size-1];
}
template<typename T>
void Stack<T>::CheckCapacity()
{
       if (_size >= _capacity)
       {
              int NewCapacity = _capacity * 2 + 3;
              T* tmp1= new T[NewCapacity];
              T* tmp2 = new T[NewCapacity];
              for (int i = 0; i < _size; i++)
              {
                     tmp1[i] = _ptr[i];
              }
              delete[] _ptr;
              _ptr = tmp1;
              for (int i = 0; i < _size; i++)
              {
                     tmp2[i] = _min[i];
              }
              delete[] _min;
              _min = tmp2;
              _capacity = NewCapacity;
       }
}

2、因为栈是后进先出,而队列是先进先出,所以我们在用两个栈实现一个队列的时候,就要用两个栈来回交换,是它能够满座先进先出的特点。

template<typename T>
class Queue
{
public:
       void Push(const T& data);
       void Pop();
       T& Front();
       T& Back();
       bool Empty();
       size_t Size();
protected:
       stack<T> s1;
       stack<T> s2;
};
template<typename T>
void Queue<T>::Push(const T& data)
{
       s1.push(data);
}
template<typename T>
void Queue<T>::Pop()
{
       assert(s1.size() >= 0);
       while (s1.size()>1)
       {
              s2.push(s1.top());
              s1.pop();
       }
       s1.pop();
       while (!s2.empty())
       {
              s1.push(s2.top());
              s2.pop();
       }
}
template<typename T>
T& Queue<T>::Front()
{
       assert(s1.size ()>= 0);
       while (s1.size()>1)
       {
              s2.push(s1.top());
              s1.pop();
       }
       T& ebp=s1.top();
       while (!s2.empty())
       {
              s1.push(s2.top());
              s2.pop();
       }
       return ebp;
}
template<typename T>
T& Queue<T>::Back()
{
       return s1.top();
}
template<typename T>
bool Queue<T>::Empty()
{
       return s1.empty();
}
template<typename T>
size_t Queue<T>::Size()
{
       return s1.size();
}

优化:
    用两个栈实现一个队列的时候,可以将一个将一个栈固定为入队序列栈,将另一个栈固定为出队序列栈,只要出队序列栈不为空,我们就一直从出队序栈中Pop数据(Pop完之后不用再将数据倒回到入队栈中)。但是注意在size和empty的时候,是两个栈都要同时判断,还有就是在返回队尾的时候有可能出现入队栈为空,出队栈不为空,这时候就需要将出队栈的元素再倒回到入队栈中。


template<typename T>
class Queue
{
public:
       void Push(const T& data);
       void Pop();
       size_t Size();
       bool Empty();
       T& Front();
       T& Back();
private:
       stack<T> _s1;           //_s1作为入队
       stack<T> _s2;           //_s2作为出队
};
template<typename T>
void Queue<T>::Push(const T& data)
{
       _s1.push(data);
}
template<typename T>
void Queue<T>::Pop()
{
       assert((_s1.size()+_s2.size()));           //两个栈都为空,则队列已空
       if (_s2.empty())                           //如果_s2以空,则需要把_s1中的元素导入_s2中
       {
              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()
{
       if (_s1.empty() && _s2.empty())      //如果两个栈都为空,则返回true
       {
              return true;
       }
       else
       {
              return false;
       }
}
template<typename T>
T& Queue<T>::Front()
{
       assert((_s1.size() + _s2.size()));           //两个栈都为空,则队列已空
       if (_s2.empty())                           //如果_s2以空,则需要把_s1中的元素导入_s2中
       {
              while (!_s1.empty())
              {
                     _s2.push(_s1.top());
                     _s1.pop();
              }
       }
       return _s2.top();
}
template<typename T>
T& Queue<T>::Back()
{
       assert((_s1.size() + _s2.size()));           //两个栈都为空,则队列已空
       if (_s1.empty())                    //_s1为空,则要把_s2栈中元素导入_s1
       {
              while (!_s2.empty())
              {
                     _s1.push(_s2.top());
                     _s2.pop();
              }
       }
       return _s1.top();
}






3、同样的,因为只要用两个队列来回交换,使得能够先进后出就行。

template<typename T>
class Stack
{
public:
       void Push(const T& data);
       void Pop();
       T& Top();
       bool Empty();
       size_t Size();
private:
       queue<T> q1;
       queue<T> q2;
};
template<typename T>
void Stack<T>::Push(const T& data)
{
       q1.push(data);
}
template<typename T>
void Stack<T>::Pop()
{
       assert(q1.size()>=0);
       while (q1.size()>1)
       {
              q2.push(q1.front());
              q1.pop();
       }
       q1.pop();
       while (!q2.empty())
       {
              q1.push(q2.front());
              q2.pop();
       }
}
template<typename T>
T& Stack<T>::Top()
{
       return  q1.back();
}
template<typename T>
bool Stack<T>::Empty()
{
       return q1.empty();
}
template<typename T>
size_t Stack<T>::Size()
{
       return  (size_t)q1.size();
}



优化:两个队列实现一个栈,用两个指针分别指向一个空队列和一个非空队列,向非空队列中插入元素(都为空的话随便插入哪一个队列),在抛出的时候需要将非空队列的元素导入到空队列中Pop完之后不必再倒回去(提高半效率)。

template<typename T>
class Stack
{
public:
       void Push(const T& data);
       void Pop();
       T& Top();
       size_t Size();
       bool Empty();
private:
       queue<T> _q1;
       queue<T> _q2;
};
template<typename T>
void Stack<T>::Push(const T& data)
{
       向不空的队列里面插入数据
       if (!_q2.empty())          //如果q2不为空
       {
              _q2.push(data);
       }
       else
       {
              _q1.push(data);
       }
}
template<typename T>
void Stack<T>::Pop()
{
       assert((_q1.size()+_q2.size()));    //两个队列不能同时为空
       queue<T> *tmp1= NULL;    //记录不空的队列
       queue<T> *tmp2 = NULL;    //记录空的队列
       if (_q1.empty())          //如果_q1为空
       {
              tmp1 = &_q2;
              tmp2 = &_q1;
       }
       else
       {
              tmp1 = &_q1;
              tmp2 = &_q2;
       }
       while (tmp1->size() > 1)
       {
              tmp2->push(tmp1->front());
              tmp1->pop();
       }
       tmp1->pop();
}
template<typename T>
T& Stack<T>::Top()
{
       assert((_q1.size() + _q2.size()));    //两个队列不能同时为空
       queue<T> *tmp1 = NULL;    //记录不空的队列
       if (_q1.empty())          //如果_q1为空
       {
              tmp1 = &_q2;
       }
       else
       {
              tmp1 = &_q1;
       }
       return tmp1->back();         //返回不空的队列的尾部元素
}
template<typename T>
size_t Stack<T>::Size()
{
       return (_q1.size() + _q2.size());
}
template<typename T>
bool Stack<T>::Empty()
{
       return (_q1.empty() && _q2.empty());
}





4、要判断出栈入栈序列的合法性,最常见的方法就是模拟整个过程。

template<typename T>
class StackLegality
{
public:
       void SetInArray(const T& data);        //输入入栈序列
       void SetOutAaary(const T& data);       //输入出栈序列
       bool DecideLegality();
private:
       stack<T> s;
       vector<T> InArray;
       vector<T> OutArray;
};
template<typename T>
void StackLegality<T>::SetInArray(const T& data)        //输入入栈序列
{
       InArray.push_back(data);
}
template<typename T>
void StackLegality<T>::SetOutAaary(const T& data)       //输入出栈序列
{
       OutArray.push_back(data);
}
template<typename T>
bool StackLegality<T>::DecideLegality()
{
       if (InArray.size() != OutArray.size())  //如果入栈序列与出栈序列的个数不相等,则一定不合法
       {
              return false;
       }
       int sz = (int)InArray.size();
       int j = 0;
       int i = 0;
       while (i<sz)
       {
              if(i<sz&&s.empty())     //如果栈为空,则需要入栈
              {
                     s.push(InArray[i]);
                     i++;
              }
              while (i<sz&&s.top() != OutArray[j])   //如果栈顶元素与出栈序列不相等,则一直入栈
              {
                     s.push(InArray[i]);
                     i++;
              }
              while (!s.empty() && s.top() == OutArray[j])
              {
                     s.pop();
                     j++;
                     int i1 = i;
                     int j1 = j;
                     while (i1<sz)
                     {
                           if (i1<sz&&s.empty())     //如果栈为空,则需要入栈
                           {
                                  s.push(InArray[i1]);
                                  i1++;
                           }
                           while (i1<sz&&s.top() != OutArray[j1])   //如果栈顶元素与出栈序列不相等,则一直入栈
                           {
                                  s.push(InArray[i1]);
                                  i1++;
                           }
                           while (!s.empty() && s.top() == OutArray[j1])
                           {
                                  s.pop();
                                  j1++;
                           }
                     }
                     if (j1 == sz)
                     {
                           return true;
                     }
                     else
                     {
                           j--;
                           while ((int)s.size()>=i)
                           {
                                  s.pop();
                           }
                           s.push(InArray[i-1]);
                           s.push(InArray[i]);
                           i++;
                     }
              }
       }
       if (j == sz)
       {
              return true;
       }
       else
       {
              return false;
       }
}


5、用一个数组实现两个栈这个问题有两种办法。一种是将数组按照奇偶顺序分成两部分,分别是奇数栈和偶数栈。另一种办法就是分别以数组的首部和尾部为栈底,实现一个栈。
例:


第一种:
template<typename T>
class DoubleStack
{
public:
       DoubleStack()
              :_array(NULL)
              , _size(0)
              , _capacity(0)
              , _top1(0)          //第一个栈的栈顶
              , _top2(1){}        //第二个栈的栈顶
       ~DoubleStack()
       {
              delete[] _array;
       }
public:
       void Push(const T& data,int flag=0);
       void Pop(int flag=0);
       T& Top(int flag=0);
       size_t Size(int flag=0);
       bool Empty(int flag=0);
private:
       void CheckCapacity();
private:
       T* _array;
       int _top1;       //第一个栈的栈顶
       int _top2;       //第二个栈的栈顶
       int _size;
       int _capacity;
};
template<typename T>
void DoubleStack<T>::CheckCapacity()
{
       if (_size >= _capacity)
       {
              int NewCapacity = 2 * _capacity + 2;
              T* tmp = new T[NewCapacity];
              for (int i = 0; i < _size; i++)
              {
                     tmp[i] = _array[i];
              }
              delete[] _array;
              _array = tmp;
              _capacity = NewCapacity;
       }
}
template<typename T>
T& DoubleStack<T>::Top(int flag)
{
       if (flag == 0)
       {
              assert(_top1>0);
              return _array[_top1-2];
       }
       else
       {
              assert(_top2>1);
              return _array[_top2 - 2];
       }
}
template<typename T>
void DoubleStack<T>::Push(const T& data, int flag)
{
       CheckCapacity();
       if (flag == 0)
       {
              _array[_top1] = data;
              _top1+= 2;
              if (_top1 > _top2)
              {
                     _size += 2;
              }
       }
       else
       {
              _array[_top2] = data;
              _top2 += 2;
              if (_top1<_top2)
              {
                     _size += 2;
              }
    }
}
template<typename T>
void DoubleStack<T>::Pop(int flag)
{
       if (flag == 0)
       {
              assert(_top1>0);
              _top1 -= 2;
              if (_top1>_top2)
              {
                     _size-= 2;
              }
       }
       else
       {
              assert(_top2>1);
              _top2 -= 2;
              if (_top1<_top2)
              {
                     _size -= 2;
              }
       }
}
template<typename T>
size_t DoubleStack<T>::Size(int flag)
{
       if (flag ==0)
       {
              return (size_t)(_top1 / 2);
       }
       else
       {
              return (size_t)((_top2 - 1) / 2);
       }
}
template<typename T>
bool DoubleStack<T>::Empty(int flag)
{
       if (flag == 0)
       {
              return _top1 == 0;
       }
       else
       {
              return  _top2 == 1;
       }
}

第二种:
template<typename T>
class  DoubleStack
{
public:
       DoubleStack()
              :_array(NULL)
              , _capacity(0)
              , _top1(0)
              , _top2(0){}
       ~DoubleStack()
       {
              delete[] _array;
       }
public: 
       void Push(const T& data,int flag = 0);
       T& Top(int flag = 0);
       void Pop(int flag = 0);
       size_t Size(int flag=0);
       bool Empty(int flag = 0);
private:
       void CheckCapacity();
private:
       T*  _array;
       int _capacity;
       int _top1;
       int _top2;
};
template<typename T>
void DoubleStack<T>::CheckCapacity()
{
       if (_top1==_top2)
       {
              int NewCapacity = 2 *_capacity + 4;
              T *tmp =new T[NewCapacity];
              for (int i = 0; i < _top1; i++)
              {
                     tmp[i] = _array[i];
              }
              int j = _capacity - 1;
              for (int i = NewCapacity - 1; j>_top2; --i,--j)
              {
                     tmp[i] = _array[j];
              }
              delete[] _array;
              _array = tmp;   
              size_t count =0;      //求出第二个栈的元素的个数
              if (_capacity != 0)
              {
                     count = _capacity - 1 - _top2;
              }
              _capacity = NewCapacity;
              _top2 =_capacity-1-count;     //改变_top2的值    
              cout << _capacity << endl;
       }
}
template<typename T>
void DoubleStack<T>::Push(const T& data,int flag = 0)
{
       CheckCapacity();
       if (flag == 0)
       {
              _array[_top1++] = data;
       }
       else
       {
              _array[_top2--] = data;
       }
}
template<typename T>
T& DoubleStack<T>::Top(int flag = 0)
{
       if (flag == 0)
       {
              assert(_top1>0);
              return _array[_top1 - 1];
       }
       else
       {
              assert(_top2<_capacity-1);
              return _array[_top2+1];
       }
}
template<typename T>
void DoubleStack<T>::Pop(int flag = 0)
{
       if (flag == 0)
       {
              assert(_top1>0);
              _top1--;
       }
       else
       {
              assert(_top2<_capacity - 1);
              _top2++;
       }
}
template<typename T>
size_t DoubleStack<T>::Size(int flag = 0)
{
       if (flag == 0)
       {
              return (size_t)_top1;
       }
       else
       {
              return (size_t)(_capacity-1-_top2);
       }
}
template<typename T>
bool DoubleStack<T>::Empty(int flag = 0)
{
       if (flag == 0)
       {
              return _top1 == 0;
       }
       else
       {
              return _top2 == (_capacity - 1);
       }
}





  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值