}
}
public int pop(int stackNum) {
int topVal = peek(stackNum);
if (size[stackNum] > 0)
size[stackNum] -= 1;
return topVal;
}
public int peek(int stackNum) {
if (size[stackNum] == 0)
return -1;
return arr[stackNum*stackSize+size[stackNum]-1];
}
public boolean isEmpty(int stackNum) {
return size[stackNum] == 0;
}
}
Q3.2 栈的最小值
请设计一个栈,除了常规栈支持的pop与push函数以外,还支持min函数,该函数返回栈元素中的最小值。执行push、pop和min操作的时间复杂度必须为O(1)。
示例:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
思路:
利用一个min变量标记当前的最小栈内元素。压栈时,如果最小元素发生变更,就把当前最小元素也进行压栈,标记这一次的最小元素变更情况。出栈时,如果遇到当前最小值与栈顶元素相同的情况,就连着这个元素一起弹出,并将当前最小值更新为这个元素的下一个元素。理论上这个方式比双栈更省空间。
class MinStack {
/**
- initialize your data structure here.
*/
Stack stack;
//将最小值初始化为整型的最大值
int min = Integer.MAX_VALUE;
public MinStack() {
//初始化一个栈
stack = new Stack();
}
public void push(int x) {
//当min==x时要重新存一下最小值,否则最小的值min会出现两次
//一次是当前的min,一次是维护当前min的第一个值
//如果if的条件改为min>x,则会影响pop()出栈的逻辑
if (min >= x) {
stack.push(min);
//维护最小值序列的第一个值(最小),并赋值给min
min = x;
}
//入栈
stack.push(x);
}
public void pop() {
//栈为空时返回空即可
if (stack.isEmpty()) {
return;
}
//长度为1时其实只存了min的初值,没有存其他值
if (stack.size() == 1) {
min = Integer.MAX_VALUE;
//min==top()说明栈顶元素是一段维护最小值序列的第一个值(即最小值)
} else if (min == top()) {
//先把这个最小值弹出
stack.pop();
//此时的栈顶元素是之前入栈时额外存入的最小值
min = top();
}
//出栈
stack.pop();
}
public int top() {
//此处直接调用java中与stack相关的API即可
return (int)stack.peek();
}
public int getMin() {
//min可以随时返回,达到了时间复杂度必须为O(1)的要求
return min;
}
}
/**
-
Your MinStack object will be instantiated and called as such:
-
MinStack obj = new MinStack();
-
obj.push(x);
-
obj.pop();
-
int param_3 = obj.top();
-
int param_4 = obj.getMin();
*/
Q3.3 堆盘子
堆盘子。设想有一堆盘子,堆太高可能会倒下来。因此,在现实生活中,盘子堆到一定高度时,我们就会另外堆一堆盘子。请实现数据结构SetOfStacks,模拟这种行为。SetOfStacks应该由多个栈组成,并且在前一个栈填满时新建一个栈。此外,SetOfStacks.push()和SetOfStacks.pop()应该与普通栈的操作方法相同(也就是说,pop()返回的值,应该跟只有一个栈时的情况一样)。 进阶:实现一个popAt(int index)方法,根据指定的子栈,执行pop操作。
示例1:
输入:
[“StackOfPlates”, “push”, “push”, “popAt”, “pop”, “pop”]
[[1], [1], [2], [1], [], []]
输出:
[null, null, null, 2, 1, -1]
示例2:
输入:
《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享
[“StackOfPlates”, “push”, “push”, “push”, “popAt”, “popAt”, “popAt”]
[[2], [1], [2], [3], [0], [0], [0]]
输出:
[null, null, null, null, 2, 1, 3]
class StackOfPlates {
//存储多个栈的容器
private List<Stack> stackList;
//盘子高度的最大值
private int cup;
public StackOfPlates(int cap) {
//构造函数完成初始化的功能
this.cup = cap;
stackList = new ArrayList<>();
}
public void push(int val) {
if (cup <= 0) {
return;
}
//这两个逻辑或的条件一定不能反过来写,只有栈不为空时才能有size==cup的判断
if (stackList.isEmpty() || stackList.get(stackList.size() - 1).size() == cup) {
//新建一个栈存入容器
Stack stack = new Stack();
stack.push(val);
stackList.add(stack);
return;
}
//栈未达到最大值就从容器中最后一个栈的末尾入栈
stackList.get(stackList.size() - 1).push(val);
}
public int pop() {
//直接调用已定义好的方法,下标参数为容器中最后一个栈的下标
return popAt(stackList.size() - 1);
}
public int popAt(int index) {
//下标越界
if (index < 0 || index >= stackList.size()) {
return -1;
}
//得到容器中下标对应的栈
Stack stack = stackList.get(index);
//栈为空
if (stack.isEmpty()) {
return -1;
}
//出栈
int res = stack.pop();
//栈为空时要把这个空栈删除
if (stack.isEmpty()) {
stackList.remove(index);
}
//将出栈的元素返回
return res;
}
}
/**
-
Your StackOfPlates object will be instantiated and called as such:
-
StackOfPlates obj = new StackOfPlates(cap);
-
obj.push(val);
-
int param_2 = obj.pop();
-
int param_3 = obj.popAt(index);
*/
Q3.4 化栈为队
实现一个MyQueue类,该类用两个栈来实现一个队列。
示例:
MyQueue queue = new MyQueue();
queue.push(1);
queue.push(2);
queue.peek(); // 返回 1
queue.pop(); // 返回 1
queue.empty(); // 返回 false
我们知道:同一段序列,分别存进一个栈和一个队列,那么出栈序列T和出队序列S顺序刚好是相反的。
那么,假如我们有两个栈的话,一段序列list
通过第一个栈后,再压入第二个栈,这时第二个栈的出栈序列应该和list
直接压入队列后的出队序列是一样的。
既然如此,我们用两个栈就可以模拟队列,一个栈专门用来存入数据,记为StackWrite
;一个栈专门用来读取数据,记为StackRead
。基于上面的结论,我们每次入队时,就把数据压入StackWrite
,每次读数据时,就把StackWrite
中的数据再压入StackRead
,这时StackRead
中的栈顶元素
就是我们所期望的队首元素
。
在出队的时候,要注意一点:
-
如果
StackRead
中有数据,那么就直接弹出StackRead
的栈顶元素; -
如果
StackRead
为空,先考虑把StackWrite
中的元素压入StackRead
,再弹出StackRead
的栈顶元素。
class MyQueue {
Stack stackWrite; // 存数据
Stack stackRead; // 读数据
/** Initialize your data structure here. */
public MyQueue() {
stackWrite = new Stack<>();
stackRead = new Stack<>();
}
/** Push element x to the back of queue. */
public void push(int x) {
stackWrite.push(x);
}
/** Removes the element from in front of queue and returns that element. */
public int pop() {
peek();
return stackRead.pop();
}
/** Get the front element. */
public int peek() {
if (!stackRead.isEmpty()) {
return stackRead.peek();
}
while (!stackWrite.isEmpty()) {
stackRead.push(stackWrite.pop());
}
return stackRead.peek();
}
/** Returns whether the queue is empty. */
public boolean empty() {
return stackRead.isEmpty() && stackWrite.isEmpty();
}
}
/**
-
Your MyQueue object will be instantiated and called as such:
-
MyQueue obj = new MyQueue();
-
obj.push(x);
-
int param_2 = obj.pop();
-
int param_3 = obj.peek();
-
boolean param_4 = obj.empty();
*/
Q3.5 栈排序
栈排序。 编写程序,对栈进行排序使最小元素位于栈顶。最多只能使用一个其他的临时栈存放数据,但不得将元素复制到别的数据结构(如数组)中。该栈支持如下操作:push、pop、peek 和 isEmpty。当栈为空时,peek 返回 -1。
示例1:
输入:
[“SortedStack”, “push”, “push”, “peek”, “pop”, “peek”]
[[], [1], [2], [], [], []]
输出:
[null,null,null,1,null,2]
示例2:
输入:
[“SortedStack”, “pop”, “pop”, “push”, “pop”, “isEmpty”]
[[], [], [], [1], [], []]
输出:
[null,null,null,null,null,true]
class SortedStack {
Stack p=new Stack<>();
Stack q=new Stack<>();
public SortedStack() {
}
public void push(int val) {
if(p.empty()) p.push(val);
else{
while(!p.empty()&&p.lastElement()<=val){
q.push(p.lastElement());
p.pop();
}
p.push(val);
while(!q.empty()){
p.push(q.lastElement());
q.pop();
}
}
}
public void pop() {
if(!p.empty()) p.pop();
}