美文网首页
栈和队列

栈和队列

作者: isuntong | 来源:发表于2020-02-08 12:21 被阅读0次

    剑指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
        }
    
    

    相关文章

      网友评论

          本文标题:栈和队列

          本文链接:https://www.haomeiwen.com/subject/odnbxhtx.html