剑指ffer 09. 用两个栈实现队列(难度:简单)
**题目:**用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )
解题思路:
用两个栈实现一个队列,要利用栈的后入先出特性实现队列的先入先出特性,其中一个栈存储当前入栈的元素,当需要出栈时调用第二个栈进行出栈,第二个栈的元素是第一个元素依次出栈之后入到第二个栈的;这样之后出栈的元素就能保证是先入先出的顺序了。
C++实现:
class CQueue {
private:
//一个保存入栈的元素,一个用来出栈
stack<int> inStack, outStack;
void in2out() {
while (!inStack.empty()) {
//进行instack到outstack的数据传输,可能用到多次因此封装为一个函数
outStack.push(inStack.top());
inStack.pop();
}
}
public:
CQueue() {}
void appendTail(int value) {
//入栈就直接push到instack中
inStack.push(value);
}
int deleteHead() {
if (outStack.empty()) {
//如果两个栈都为空,就没有元素可以删除,返回-1
if (inStack.empty()) {
return -1;
}
//如果instack中还有元素,进行元素传输之后再返回要删除的值
in2out();
}
int value = outStack.top();
outStack.pop();
return value;
}
};
复杂度分析:
- 时间复杂度:O(1),deleteHead 为均摊 O(1)。对于每个元素,至多入栈和出栈各两次,故均摊复杂度为 O(1)。
- 空间复杂度:O(n)。其中 n 是操作总数。对于有 n 次 appendTail 操作的情况,队列中会有 n 个元素,故空间复杂度为 O(n)。
剑指offer 30. 包含min函数的栈
**题目:**定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
解题思路:
题目的难点在于需要动态记录当前栈中元素的最小值,可以定义一个辅助栈,存储对应当前栈中元素的最小值。
C++实现:
class MinStack {
stack<int> x_stack;
stack<int> min_stack;
public:
MinStack() {
//此时先存入一个最大值,避免了后面判断栈是否为空的麻烦,可直接与此时的栈顶元素进行比较进行存储最小值
min_stack.push(INT_MAX);
}
void push(int x) {
x_stack.push(x);
//存储当前对应栈中的元素的最小值
min_stack.push(::min(min_stack.top(), x));
}
void pop() {
//如果出栈的话,两个栈都出
x_stack.pop();
min_stack.pop();
}
int top() {
//返回栈顶元素
return x_stack.top();
}
int min() {
//返回当前的最小值
return min_stack.top();
}
};
Python3实现:
class MinStack:
def __init__(self):
self.stack = []
self.min_stack = [math.inf]
def push(self, x: int) -> None:
self.stack.append(x)
self.min_stack.append(min(x, self.min_stack[-1]))
def pop(self) -> None:
# python的pop方法可以返回元素的值,不用像c++那样两步
self.stack.pop()
self.min_stack.pop()
def top(self) -> int:
return self.stack[-1]
def min(self) -> int:
return self.min_stack[-1]
复杂度分析:
- 时间复杂度:对于题目中的所有操作,时间复杂度均为 O(1)。因为栈的插入、删除与读取操作都是 O(1),我们定义的每个操作最多调用栈操作两次。
- 空间复杂度:O(n),其中 n 为总操作数。最坏情况下,我们会连续插入 n 个元素,此时两个栈占用的空间为 O(n)。