栈和队列

2020-02-08  本文已影响0人  isuntong

剑指offer所有的题目总结

牛客

  1. 滑动窗口的最大值

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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<Integer> maxInWindows1(int [] num, int size) {
        ArrayList<Integer> res = new ArrayList<>();
        if (num == null || size <= 0 || num.length < size) {
            return res;
        }
        
        // 暴力破解法
        int len = num.length;
        int maxIdx = len - size;
        for (int i=0; i<= maxIdx; i++) {
            // 获取当前序列的最大值
            int curMax = num[i];
            for (int j=i+1; j<i+size; j++) {
                curMax = curMax > num[j] ? curMax : num[j];
            }
            // 最大值加入res
            res.add(curMax);
        }
        
        return res;
    }

双端队列法:

public static ArrayList<Integer> maxInWindows2(int[] num, int size) {
        ArrayList<Integer> maxWindows = new ArrayList<>();
        if (num == null || size == 0 || num.length == 0 || num.length < size)
            return maxWindows;
        Deque<Integer> dq = new LinkedList<>();
        for (int i = 0; i < size; i++) {
            // 如果已有数字小于待存入的数据,         
            // 这些数字已经不可能是滑动窗口的最大值              
            // 因此它们将会依次地从队尾删除
            while (!dq.isEmpty() && num[i] > num[dq.getLast()])
                dq.removeLast();
            dq.addLast(i);
        }
        //System.out.println(dq);
        for (int i = size; i < num.length; i++) {
            maxWindows.add(num[dq.getFirst()]);
            while (!dq.isEmpty() && num[i] >= num[dq.getLast()])
                dq.removeLast();
 
            if (!dq.isEmpty() && dq.getFirst() <= i - size)
                dq.removeFirst();
            dq.addLast(i);
        }
        maxWindows.add(num[dq.getFirst()]);
        return maxWindows;
    }
  1. 用两个栈实现队列

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();
    
    public void push(int node) {
        while(!stack2.isEmpty()) {
            stack1.push(stack2.pop());
        }
        stack1.push(node);
    }
    
    public int pop() {
        while(!stack1.isEmpty()) {
            stack2.push(stack1.pop());
        }
        return stack2.pop();
    }

只是考虑栈和队列的特点

  1. 包含min函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。

    /* 
    * 思路:用一个栈stack保存数据,用另外一个栈min保存依次入栈最小的数  
    * 比如,stack中依次入栈,5, 4, 3, 8, 10,11,12,1  
    * 则min依次入栈,5, 4, 3, 3, 3, 3, 3, 1 
    * 每次入栈的时候,如果入栈的元素比min中的栈顶元素小或等于则入栈,否则入stack的栈顶元素。  
    * 保持stack中和min中保持相同个数的元素 ,同时保持min的栈顶是此时原栈的最小值。
    */
        Stack<Integer> stackData = new Stack<>(); //声明时候的异同
        Stack<Integer> stackMin = new Stack<Integer>();
        public void push(int node) {
            stackData.push(node);
         // 如果min为空或者node比min栈中的元素小,则入min栈  
            if(stackMin.size() == 0 || stackMin.peek() > node)
                stackMin.push(node);
            else // 否则把min栈中的顶部元素重复入栈
                stackMin.push(stackMin.peek());
        }
        
        public void pop() {//因为时刻保持两个栈的高度相同,所以两个都pop,时刻保持min的栈顶是原栈的最小值。
            //如果返回应该是返回原栈的。
            if(!stackData.isEmpty()){
                stackData.pop();
                stackMin.pop();
            }
        }
        
        public int top() {
            return stackData.peek();
        }
        
        public int min() {
            return stackMin.peek();
        }
  1. 栈的压入、弹出序列

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

/**借用一个辅助的栈,遍历压栈顺序,先讲第一个放入栈中,这里是1,
    然后判断栈顶元素是不是出栈顺序的第一个元素,这里是4,很显然1≠4,所以我们继续压栈,
    直到相等以后开始出栈,出栈一个元素,则将出栈顺序向后移动一位,直到不相等,
    这样循环等压栈顺序遍历完成,如果辅助栈还不为空,说明弹出序列不是该栈的弹出顺序。
    举例: 
    入栈1,2,3,4,5 
   出栈4,5,3,2,1 
   首先1入辅助栈,此时栈顶1≠4,继续入栈2 
   此时栈顶2≠4,继续入栈3 
   此时栈顶3≠4,继续入栈4 
   此时栈顶4=4,出栈4,弹出序列向后一位,此时为5,,辅助栈里面是1,2,3 
   此时栈顶3≠5,继续入栈5 
   此时栈顶5=5,出栈5,弹出序列向后一位,此时为3,,辅助栈里面是1,2,3 
  …. 
  依次执行,最后辅助栈为空。如果不为空说明弹出序列不是该栈的弹出顺序。
     * @param pushA
     * @param popA
     * @return
     */
    public boolean IsPopOrder(int[] pushA, int[] popA) {
        if (pushA == null || popA == null || pushA.length == 0
                || popA.length == 0)
            return false;
        int index = 0; //作为弹出序列的一个索引
        Stack<Integer> stack = new Stack<Integer>();
        for (int i = 0; i < pushA.length; i++) {
            stack.push(pushA[i]); 
            while (!stack.isEmpty() && stack.peek() == popA[index]) {// 当栈不为空且栈顶元
                //素等于弹出序列元素时候,就弹出一个,同时让弹出序列后移一个
                stack.pop();
                index++;
            }
        }
        return stack.isEmpty();//如果最后,栈不为空,相当于没有按照给定的弹出popA弹出完毕,
        //就说明不能按照popA,返回false
    }

上一篇下一篇

猜你喜欢

热点阅读