题目
原文:
Imagine a (literal) stack of plates. If the stack gets too high, it might topple. Therefore, in real life, we would likely start a new stack when the previous stack exceeds some threshold. Implement
a data structure SetOfStacks that mimics this. SetOfStacks should be composed of several stacks, and should create a new stack once the previous one exceeds capacity. SetOfStacks.push() and SetOfStacks.pop() should behave identically to a single stack (that
is, pop() should return the same values as it would if there were just a single stack).
FOLLOW UP
Implement a function popAt(int index) which performs a pop operation on a specific sub-stack.
译文:
想象一下,一 堆盘子,如果堆得太高,它很可能会倒,因此在现实生活中,如果盘子堆到一定高度,我们就会重新起一个堆。现在实现一个新的数据结构SetOfStack来模拟这样现象。SetOfStack当中包含很多的堆栈,当一个堆栈达到上限的时候,启用下一个堆栈。SetOfStack.push
和 SetOfStack.pop应该和普通堆栈的操作一样。
进阶:
实现一个函数popAt(int index),指定在哪个堆栈上弹出元素。
解答
以下是书本的解答
由于要和普通的堆栈的push()有相同的效果,也就是说每次push()都必须将元素放到最近使用的一个堆栈中。但是在这个堆栈已经满了情况下,那就必须建一个新的堆栈然后再入栈。那么push的实现如下:
public void push(int v) {
Stack last = getLastStack();
if (last != null && !last.isAtCapacity()) { // add to last stack
last.push(v);
} else { // must create new stack
Stack stack = new Stack(capacity);
stack.push(v);
stacks.add(stack);
}
}
那pop()如何实现呢?和push()差不多,也一定要在最近的一个堆栈上操作。但是如果最后一个堆栈是空的话,就应该将其移除。
public int pop()
{
Stack last = getLastStack();
System.out.println(stacks.size());
int v = last.pop();
if (last.size == 0) stacks.remove(stacks.size() - 1);
return v;
}
那进阶的问题这么处理呢?
这个问题确实有点难度。实现起来也比较麻烦,因为整个系统看起来应该像一个“翻转”系统。如果我从堆栈1中弹出一个元素,那么我们需要将堆栈2底部的元素压到堆栈1的顶端。堆栈3的元素要到堆栈2....
注:你可能会不同意我的说法。认为实现这个函数不需要“翻转”整个堆栈。系统中的每个堆栈并不需要都是满栈的,这样的话也可以省下很多的时间复杂度,特别是在堆栈非常大的时候。但是如果假设除了最后一个堆栈之外,所有的堆栈必须满栈的话,这样的方法就不行了。具体采用什么样的结构,你可以在面试时和面试官好好沟通然后决定。
class SetOfStacks
{
ArrayList<Stack> stacks = new ArrayList<Stack>();
public int capacity; //容量
public SetOfStacks(int capacity)
{
this.capacity = capacity;
}
public Stack getLastStack()
{
if (stacks.size() == 0) return null;
return stacks.get(stacks.size() - 1);
}
public void push(int v) {
Stack last = getLastStack();
if (last != null && !last.isAtCapacity()) { // add to last stack
last.push(v);
} else { // must create new stack
Stack stack = new Stack(capacity);
stack.push(v);
stacks.add(stack);
}
}
public int pop()
{
Stack last = getLastStack();
System.out.println(stacks.size());
int v = last.pop();
if (last.size == 0) stacks.remove(stacks.size() - 1);
return v;
}
public int popAt(int index)
{
return leftShift(index, true);
}
public int leftShift(int index, boolean removeTop)
{
Stack stack = stacks.get(index);
int removed_item;
if (removeTop) removed_item = stack.pop();
else removed_item = stack.removeBottom();
if (stack.isEmpty())
{
stacks.remove(index);
}
else if (stacks.size() > index + 1)
{
int v = leftShift(index + 1, false);
stack.push(v);
}
return removed_item;
}
}
class Stack
{
private int capacity;
public Node top, bottom;
public int size = 0;
public Stack(int capacity)
{
this.capacity = capacity;
}
public boolean isAtCapacity()
{
return capacity == size;
}
public void join(Node above, Node below)
{
if (below != null) below.above = above;
if (above != null) above.below = below;
}
public boolean push(int v)
{
if (size >= capacity) return false;
size++;
Node n = new Node(v);
if (size == 1) bottom = n;
join(n, top);
top = n;
return true;
}
public int pop()
{
Node t = top;
top = top.below;
size--;
return t.value;
}
public boolean isEmpty()
{
return size == 0;
}
public int removeBottom()
{
Node b = bottom;
bottom = bottom.above;
if (bottom != null) bottom.below = null;
size--;
return b.value;
}
}
--- EOF---