LeetCode Stack / Design专题专题部分,更多说明请见LeetCode Array专题
232. Implement Queue using Stacks
Implement the following operations of a queue using stacks.
- push(x) – Push element x to the back of queue.
- pop() – Removes the element from in front of queue.
- peek() – Get the front element.
- empty() – Return whether the queue is empty.
Notes:
- You must use only standard operations of a stack – which means only
push to top
,peek/pop from top
,size
, andis empty
operations are valid.- Depending on your language, stack may not be supported natively. You may simulate a stack by using a list or deque (double-ended queue), as long as you use only standard operations of a stack.
- You may assume that all operations are valid (for example, no pop or peek operations will be called on an empty queue).
译:使用栈来实现一个拥有以下操作的队列:
- push(x) – Push element x to the back of queue.
- pop() – Removes the element from in front of queue.
- peek() – Get the front element.
- empty() – Return whether the queue is empty.
注意:
你必须仅仅使用标准的栈操作,意味着存在这几个可用的操作:push到栈顶,从栈顶peek/pop,size和is empty操作
实现
public class TwoQueueUsingStacks {
Stack<Integer> stackA = new Stack<>();
Stack<Integer> stackB = new Stack<>();
// Push element x to the back of queue.
public void push(int x) {
stackA.push(x);
}
// Removes the element from in front of queue.
public void pop() {
if (stackB.empty()) {
while (!stackA.isEmpty()) {
stackB.push(stackA.pop());
}
}
stackB.pop();
}
// Get the front element.
public int peek() {
if (stackB.empty()) {
while (!stackA.isEmpty()) {
stackB.push(stackA.pop());
}
}
return stackB.peek();
}
// Return whether the queue is empty.
public boolean empty() {
return (stackA.empty()) && (stackB.empty());
}
}
问题分析
先画图,画分解图一步步的通过入栈出栈LIFO的特性就能反推出链表FIFO的行为,例如存在两个栈A 、B,将一组元素{a, b, c, d, e, f, g, h} 进行各种链表操作,只要遵循FIFO的行为就不难理解。
225. Implement Stack using Queues
Implement the following operations of a stack using queues.
- push(x) – Push element x onto stack.
- pop() – Removes the element on top of the stack.
- top() – Get the top element.
- empty() – Return whether the stack is empty.
Notes:
- You must use only standard operations of a queue – which means only
push to back
,peek/pop from front
,size
, andis empty
operations are valid.- Depending on your language, queue may not be supported natively. You may simulate a queue by using a list or deque (double-ended queue), as long as you use only standard operations of a queue.
- You may assume that all operations are valid (for example, no pop or top operations will be called on an empty stack).
Update (2015-06-11):
The class name of the Java function had been updated to MyStack instead of Stack.译:使用队列来实现以下栈的操作:
- push(x) – Push element x onto stack.
- pop() – Removes the element on top of the stack.
- top() – Get the top element.
- empty() – Return whether the stack is empty.
实现
方法一:队列A负责入栈,队列B负责中转A中的元素
以下实现方式有个不足之处就是每次B不为空时,都需要将B中的所有元素遍历一遍传给A后在A中进行相关操作,导致效率低下。
class MyStack {
LinkedList<Integer> queueA = new LinkedList<>();
LinkedList<Integer> queueB = new LinkedList<>();
// Push element x onto stack.
public void push(int x) {
if (queueB.isEmpty()) {
queueA.add(x);
} else {
queueB.add(x);
}
}
// Removes the element on top of the stack.
public void pop() {
if (queueA.isEmpty() && queueB.isEmpty()) {
return;
}
if (queueB.isEmpty()) {
while(queueA.size() > 1) {
queueB.add(queueA.remove());
}
if (queueA.size() > 0) {
queueA.remove();
}
} else {
while(queueB.size() > 1) {
queueA.add(queueB.remove());
}
if (queueB.size() > 0) {
queueB.remove();
}
}
}
// Get the top element.
public int top() {
if(queueA.isEmpty() && queueB.isEmpty()) {
return 0;
}
if (queueB.isEmpty()) {
while(queueA.size() > 1) {
queueB.add(queueA.remove());
}
int lastElement = queueA.peek();
queueB.add(queueA.remove());
return lastElement;
} else {
while(queueB.size() > 1) {
queueA.add(queueB.remove());
}
int lastElement = queueB.peek();
queueA.add(queueB.remove());
return lastElement;
}
}
// Return whether the stack is empty.
public boolean empty() {
return (queueA.isEmpty() && queueB.isEmpty());
}
}
问题分析
关于栈和队列的相互实现,主要考察的是两者的概念和原理的清晰度,并且在队列实现中,需要了解相关语言的知识点,例如Java中实现队列结构的类有LinkedList,那么LinkedList中的哪些方法符合条件,就可以去看看Java源码。这里给出LeetCode中对这次的总结,各类操作的时间复杂度都分析明确,值得仔细看看:implement-stack-using-queues
155. Min Stack
Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
- push(x) – Push element x onto stack.
- pop() – Removes the element on top of the stack.
- top() – Get the top element.
- getMin() – Retrieve the minimum element in the stack.
译:设计一个支持push / pop / top操作的栈,能够在常量时间取得最小值
Example:
MinStack minStack = new MinStack(); minStack.push(-2); minStack.push(0); minStack.push(-3); minStack.getMin(); --> Returns -3. minStack.pop(); minStack.top(); --> Returns 0. minStack.getMin(); --> Returns -2.
实现
public class MinStack {
Stack<Integer> minValueStack = new Stack<>();
Stack<Integer> mStack = new Stack<>();
public void push(int x) {
mStack.push(x);
if (minValueStack.isEmpty() || minValueStack.peek() >= x) {
minValueStack.push(x);
}
}
public void pop() {
if (mStack.isEmpty()) return;
else {
if (!minValueStack.isEmpty()) {
if (mStack.peek().equals(minValueStack.peek())) {
minValueStack.pop();
}
}
mStack.pop();
}
}
public int top() {
if (!mStack.isEmpty()) {
return mStack.peek();
} else return 0;
}
public int getMin() {
if (minValueStack.isEmpty()) return 0;
else return minValueStack.peek();
}
}
问题分析
题中为了取当前栈mStack中最小值,一开始想的是用常量来做一个缓存,但发现最小值是根据栈mStack的内容动态变化的,这就意味着需要一个额外的栈minValueStack进行缓存。别的就是正常的栈操作,注意边界和空栈的情况即可。不过发现一个问题,如果原始栈一直处于递减状态,那么栈minValueStack会一直递增花费更多的空间,而一旦题目对空间的要求比较苛刻,这种方式就不再适用。