目录
面试题9I:用两个栈实现队列
面试题9II:用两个队列实现一个栈
面试题30:包含min函数的栈
面试题31:栈的压入、弹出序列
面试题59:滑动窗口的最大值
题目:用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
分析:进队列每次都压入stack1。出队列:若stack2不为空,直接出栈即可;否则将stack1的元素依次出栈并压入stack2中。
Deque stack1 = new LinkedList();
Deque stack2 = new LinkedList();
public void appendTail(int value) {
stack1.add(value);
}
public int deleteHead() {
if(stack2.isEmpty()){
while(!stack1.isEmpty()){
stack2.add(stack1.poll());
}
}
if(stack2.isEmpty())//队列为空
return -1;
else
return stack2.poll();
}
题目:用两个队列来实现一个栈,完成栈的Push和Pop操作。 栈中的元素为int类型。
分析:始终保持一个队列为空,进行“互倒”即可。
Queue queue1 = new ArrayDeque();
Queue queue2 = new ArrayDeque();
public void push(int node) {
if(queue1.isEmpty())
queue2.add(node);
else
queue1.add(node);
}
public int pop() {
if(queue1.isEmpty() && queue2.isEmpty())
return (Integer)null;
//如果queue1为空,queue2有元素, 将queue2的元素依次放入queue1中,直到最后一个元素才弹出。
if(queue1.isEmpty()){
while(queue2.size() > 1)
queue1.add(queue2.poll());
return queue2.poll();
}
if(queue2.isEmpty()){
while(queue1.size() > 1)
queue2.add(queue1.poll());
return queue1.poll();
}
return (Integer)null;
}
题目:定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
分析:每次压栈都将最小元素压入辅助栈,就能保证辅助栈的栈顶一直都是最小元素。
Stack stack = new Stack<>();
Stack auxStack = new Stack<>();
public void push(int node) {
stack.push(node);
if(auxStack.empty() || node < min())
auxStack.push(node);
else
auxStack.push(min());
}
public void pop() {
stack.pop();
auxStack.pop();
}
public int top() {
return stack.peek();
}
public int min() {
return auxStack.peek();
}
题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
分析:如果下一个弹出的数字刚好是栈顶数字,则直接弹出;如果下一个弹出的数字不在栈顶,则把压栈序列中还没有入栈的数字压入辅助栈,直到把下一个需要弹出的数字压入栈顶即可。
public boolean IsPopOrder(int [] pushA,int [] popA) {
if(pushA == null || popA == null)
return false;
if(pushA.length != popA.length || pushA.length == 0)
return false;
Stack stack = new Stack<>();
for(int i = 0,j = 0;j < pushA.length;j++){
while(stack.empty() || stack.peek() != popA[j]){
if(i >= pushA.length)
return false;
stack.push(pushA[i++]);
}
stack.pop();
}
return true;
}
题目:给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
分析:只将可能成为滑动窗口最大值的数值存入一个两端开口的队列,在存入一个数字的下标之前,首先要判断队列里已有的数字是否小于待存入的数字,如果小于则依次从队列的尾部移除。同时,如果队列头部的数字已经从窗口滑出,那么滑出的数字也要从队列头部删除。这样可以保证滑动窗口的最大值总是位于队列的头部。最后将当前元素的索引加入队列即可。
public ArrayList maxInWindows(int [] num, int size){
ArrayList res = new ArrayList<>();
if(num == null || num.length == 0 || size < 1)
return res;
LinkedList queue = new LinkedList<>();
for(int i = 0;i < num.length;i++){
// 从后面依次弹出队列中比当前num值小的元素,同时也能保证队列首元素为当前窗口最大值下标
while(!queue.isEmpty() && num[queue.peekLast()] <= num[i])
queue.pollLast();
// 当队首元素坐标对应的num不在窗口中,需要弹出
if(!queue.isEmpty() && i - queue.peekFirst() + 1 > size) {
queue.pollFirst();
}
queue.offerLast(i);
if(i >= size - 1)
res.add(num[queue.peekFirst()]);
}
return res;
}