美文网首页
栈和队列使用

栈和队列使用

作者: 你值得拥有更好的12138 | 来源:发表于2020-03-01 21:57 被阅读0次

    一、栈的使用

    栈在使用过程中,算法的运算过程应该是从后向前计算的
    在栈的不仅可以存放值还可以存放下标

    计算每日温度

    当遇到比栈顶高的温度时,开始标记结果,然后继续出栈直到计算到比当前值大的温度,然后入栈

    根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高超过该日的天数。如果之后都不会升高,请在该位置用 0 来代替。

    例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。

    提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/daily-temperatures
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    1.关键点在,栈的存储的是小标而不是值,每向前一步,就操作一遍stack

    /**
     * 根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高超过该日的天数。如果之后都不会升高,请在该位置用 0 来代替。
    
     例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
    
     提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。
    
     来源:力扣(LeetCode)
     链接:https://leetcode-cn.com/problems/daily-temperatures
     著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    
     1.关键点在,栈的存储的是小标而不是值,每向前一步,就操作一遍stack
     */
    public class EverdayTemp {
    
        public static void main(String[] args) {
            int[] temp = {73, 74, 75, 71, 69, 72, 76, 73};
            int[] result = new int[8];
    
            Stack<Integer> stack = new Stack<>();
            stack.push(0);
            for (int i = 1; i < temp.length; i++) {
    
                while(!stack.isEmpty() && temp[i] > temp[stack.peek()]){
                        result[stack.peek()]=(i-stack.pop());
                }
                stack.push(i);
    
            }
    
            System.out.println(Arrays.toString(result));
        }
    }
    
    2.计算柱状图最大面积
    同样是倒着计算的顺序,当遇到比栈顶元素低的柱状时开始计算,直到栈顶原始比当前柱状高,如果栈为空,特殊处理宽度是为当前下标而不是两个小标相减
    /**
     * LeetCode 第 84 题:给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1。
     * 求在该柱状图中,能够勾勒出来的矩形的最大面积。
     *
     * 1.当栈空时,宽度应该是游标i
     */
    public class HistogramArea {
        public static void main(String[] args) {
            int[] nums = {2,1,5,6,2,3};
            int max = new HistogramArea().maxArea(nums);
            System.out.println(String.format("最大值:%s",max));
        }
    
        private int maxArea(int[] nums){
            int maxAera = 0;
            Stack<Integer> stack = new Stack<>();
            for(int i=0;i<=nums.length;i++){
                while (!stack.isEmpty() && (i== nums.length||nums[i] < nums[stack.peek()])){
                    int height = nums[stack.pop()];
                    int width = stack.isEmpty()?i:i-1-stack.peek();
                    maxAera = Math.max(maxAera,height*width);
                }
                stack.push(i);
            }
    
            return maxAera;
        }
    }
    
    

    二、队列的使用

    队列使用比较简单,以下介绍一个特殊的队列,双端队列。
    它可以在两端都可以进出,在算法中合理的运用时可以将时间复杂度降低

    1.滑动窗口最大值

    不断向队列中加元素,保持最左端的数是最大的数,如果小于这个数就进入队列,如果大于这个数,清空队列并将当前的数入队列。注意:每次只于最左端的数进行比较
    /**

    • 给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
    • 返回滑动窗口中的最大值。
    • 示例:
    • 输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
    • 输出: [3,3,5,5,6,7]
    • 解释:
    • 滑动窗口的位置 最大值

    • [1 -3 3] -3 -1 3 1 7 3
    • 1 [3 -1 -3] 5 3 6 7 3
    • 1 3 [-1 -3 5] 3 6 7 5
    • 1 3 -1 [-3 5 3] 6 7 5
    • 1 3 -1 -3 [5 3 6] 7 6
    • 1 3 -1 -3 5 [3 6 7] 7
    • 提示:
    • 你可以假设 k 总是有效的,在输入数组不为空的情况下,1 ≤ k ≤ 输入数组的大小。
    • 来源:力扣(LeetCode)
    • 链接:https://leetcode-cn.com/problems/sliding-window-maximum
    • 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    • 1.优先队列 nlogn ,而且解决不了元素重复的问题,除非用hash
    • 2.双端队列 在插入的过程中比较大小,由于在双端队列的两端查询,插入都是O(1),
    • 所以将总的复杂度降低到了o(n),如果单向队列,复杂度就升级为n^2

    */

    
    public class SlideWindow {
    
    
        public static void main(String[] args) {
             twoHeaderQuene();
        }
    
        public static void priQueneMethod(){
            int k = 3;
            Queue<Integer> priorityQueue = new PriorityQueue<Integer>((x,y) -> (y-x));
            int[] temp = {1,3,-1,-3,5,3,6,7};
            int[] result = new int[temp.length-k+1];
            for (int i = 0; i < temp.length; i++) {
                if(i < k){
                    priorityQueue.offer(temp[i]);
                    if(i==k-1)
                        result[i-k+1]=priorityQueue.peek();
                }else {
                    priorityQueue.remove(temp[i-k]);
                    priorityQueue.offer(temp[i]);
                    result[i-k+1]=priorityQueue.peek();
                }
            }
    
            System.out.println(Arrays.toString(result));
        }
    
        public static void  twoHeaderQuene(){
            int k = 3;
            Deque<Integer> deque = new LinkedList<>();
            int[] temp = {1,-3,-1,-3,5,3,6,7};
            int[] result = new int[temp.length-k+1];
            deque.offer(0);
            for (int i = 1; i < temp.length; i++) {
    
                if(temp[deque.peekFirst()] < temp[i]){
                    deque.clear();
                    deque.offerFirst(i);
                }else {
                    deque.offer(i);
                }
    
    
                if(i>k-2){
                    result[i-k+1]=temp[deque.peekFirst()];
                }
    
            }
            System.out.println(Arrays.toString(result));
        }
    
    

    三、栈和队列的同时使用

    简单计算功能(只有加减乘除)

    注意:需要一个暂时变量存在符号,当遇到符号后的数时候再运算,乘除优先级大于加减,如遇到括号使用递归进行计算。

    /**
     * 1.使用sign符号,先赋值在计算的方式就不必回头
     * 2.队列最后一定要加一个+加号触发最后一个符号的运算
     * 3.使用递归计算括号内的值
     * 4.判断右括号要再赋值后,才能避免内层的递归队列多出一个符号
     */
    public class CaculateMachine {
        public static void main(String[] args) {
            Queue<Character> queue = new LinkedList<>();
            String temp = "10/(20+1-2)*2";
            for (int i =0;i< temp.length();i++){
                Character c = temp.charAt(i);
                queue.offer(c);
            }
            queue.offer('+');
            System.out.println(new CaculateMachine().caculate(queue));
    
        }
    
        private double caculate(Queue<Character> characters){
            double num =0;
            Character sgin='+';
            Stack<Double> stack = new Stack<>();
            while (!characters.isEmpty()){
                Character c = characters.poll();
                if(Character.isDigit(c)){
                    String s = "0.1";
                    System.out.println("==="+num*10);
                    System.out.println("==="+(num*10+c));
                    System.out.println("==="+(num*10+c-'0'));
    //                System.out.println("=="+ (s-'0'));
                    num=num*10+c-'0';
                }else if(c.equals('(')){
                    num=caculate(characters);
    
                }
                else {
                    if(sgin.equals('+')){
                        stack.push((double)num);
                    }else if(sgin.equals('-')){
                        stack.push((double)-num);
                    }else if(sgin.equals('*')){
                        stack.push(stack.pop()*num);
                    }else if(sgin.equals('/')){
                        stack.push(stack.pop()/num);
                    }
    
    
    
                    sgin=c;
                    num=0;
    
                    //写在赋值的后面,才能避免内层的递归队列多出一个符号
                    if(sgin.equals(')'))
                        break;
                }
            }
    
            double sum = 0;
            while (!stack.isEmpty()){
                double v = stack.pop();
                sum+=v;
            }
    
            return sum;
        }
    }
    
    

    相关文章

      网友评论

          本文标题:栈和队列使用

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