剑指offer之栈和队列

目录

面试题9I:用两个栈实现队列

面试题9II:用两个队列实现一个栈

面试题30:包含min函数的栈

面试题31:栈的压入、弹出序列

面试题59:滑动窗口的最大值


面试题9I:用两个栈实现队列

题目:用两个栈来实现一个队列,完成队列的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();
    }

面试题9II:用两个队列实现一个栈

题目:用两个队列来实现一个栈,完成栈的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;
    }

面试题30:包含min函数的栈

题目:定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的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();
    }

面试题31:栈的压入、弹出序列

题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列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;
    }

面试题59:滑动窗口的最大值

题目:给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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;
    }

 

你可能感兴趣的:(剑指offer)