栈和队列使用

一、栈的使用

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

计算每日温度

###当遇到比栈顶高的温度时,开始标记结果,然后继续出栈直到计算到比当前值大的温度,然后入栈
根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高超过该日的天数。如果之后都不会升高,请在该位置用 0 来代替。

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

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

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;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值