美文网首页
栈和队列使用

栈和队列使用

作者: 你值得拥有更好的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;
    }
}

相关文章

  • 算法-栈和队列算法总结

    栈和队列算法总结 1 模拟 1.1 使用栈实现队列 1.2 使用队列实现栈 2 栈的应用 2.1 栈操作 2.2 ...

  • Python实现栈和队列以及使用list模拟栈和队列

    Python实现栈和队列 Python使用list模拟栈和队列

  • 队列和栈的应用

    队列和栈的使用 标签(空格分隔): algorithm 队列和栈的应用 1.队列的应用 队列是一种常见的数据结构,...

  • 数据结构——栈和队列

    用数组实现栈和队列 用栈实现队列 用队列实现栈 栈和队列的经典算法题最小间距栈宠物收养所 数组实现栈和队列 用数组...

  • JavaScript⑦数组队列

    栈和队列: js中没有专门的栈和队列类型,都是用普通该数组模拟的。 何时: 只要希望按照顺序使用数组元素时 栈: ...

  • 栈和队列使用

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

  • 栈和队列

    用栈定义队列(出入栈) 用队列定义栈(数据队列和辅助队列)

  • leecode刷题(26)-- 用栈实现队列

    leecode刷题(26)-- 用栈实现队列 用栈实现队列 使用栈实现队列的下列操作: push(x) -- 将一...

  • js

    栈和队列: js中没有专门的栈和队列类型,都是用普通该数组模拟的。 何时: 只要希望按照顺序使用数...

  • Algorithm小白入门 -- 队列和栈

    队列和栈队列实现栈、栈实现队列单调栈单调队列运用栈去重 1. 队列实现栈、栈实现队列 队列是一种先进先出的数据结构...

网友评论

      本文标题:栈和队列使用

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