您的位置:首页 > 职场人生

关于队列和栈的几道面试题

2016-09-18 16:00 471 查看
今天来说几道简单的栈和队列相关的几道面试题:

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;
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息