代码随想录算法训练营第13天 | 150. 逆波兰表达式求值, 239. 滑动窗口最大值,347.前 K 个高频元素

代码随想录算法训练营第13天 | 150. 逆波兰表达式求值, 239. 滑动窗口最大值,347.前 K 个高频元素

150. 逆波兰表达式求值

  1. 栈适用于相邻近的元素匹配消除的操作
  2. 前面做的两题一个是相邻近的括号匹配然后消除 一个是向邻近的字母一样消除 这题是一样的原理 邻近的2个数再遇到一个运算符就消除 再添加
  3. 注意点是 第一个数和第二个数的运算顺序 第二个Pop出来的在前面
class Solution {
    public int evalRPN(String[] tokens) {
        Deque<Integer> zhan = new ArrayDeque<>();

        for(String s: tokens){
            if(s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/") ){
                int num1 = zhan.pollLast();
                int num2 = zhan.pollLast();

                if(s.equals("+")){
                    zhan.addLast(num2+num1);
                }else if(s.equals("-")){
                    zhan.addLast(num2-num1);
                }else if(s.equals("*")){
                    zhan.addLast(num2*num1);
                }else if(s.equals("/")){
                    zhan.addLast(num2/num1);
                }
                
                
            }else{
                zhan.addLast(Integer.valueOf(s));
            }

            
        }

        int res = zhan.pollLast();
        return res;








    }
}

239. 滑动窗口最大值

  1. 自定义维护一个单调队列 维护出口第一个元素最大 假如新进来的元素更大 就pop掉前面所有元素
  2. 假如新进来的元素比前面部分元素大 那么就Pop掉那部分元素
  3. 滑动的时候 判断队列出口元素是否等于需弹出元素 若不等于 则不用管 因为之前已经被pop掉了
  4. 准备新进来元素做判断时 可以用while循环 和当前队列尾部元素比大小
  5. 暴力解法为在每个滑动窗口中再遍历找最大 时间复杂度为 n*k
  6. 即用一个数组来接滑动窗口的元素 然后遍历找Max
  7. 用单调队列来找滑动窗口中的最大值 只用o(1) 因为最大值保持在队列出口
  8. 接下来在主函数中 就只需要遍历数组 每遍历一次就做一次pop push getMaxValue操作 用一个结果数组来接Max值
  9. 不过需注意 第一轮滑动窗口初始 先用一轮单独的循环装值进去 不用pop

单调队列

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums.length == 1){
            return nums;
        }
        int resLen = nums.length-k+1;
        int[] res = new int[resLen];
        Myqueue queue = new Myqueue();
        int count = 0;
        for(int i=0;i<k;i++){
            queue.push(nums[i]);
           
        }
         res[count++] = queue.getMaxValue();

         for(int i =k;i<nums.length;i++){
             queue.pop(nums[i-k]);
             queue.push(nums[i]);
             res[count++] = queue.getMaxValue();
             
         }

         return res;

    }
}


class Myqueue {
    Deque<Integer> que = new LinkedList<>();

    public void pop(int val){
        if(!que.isEmpty() && que.peekFirst()==val){
            que.pollFirst();
        }
    }


    public void push(int val){
        while(!que.isEmpty() && val>que.peekLast()){
            que.pollLast();
        }
        que.addLast(val);
    }


    public int getMaxValue(){
        return que.peekFirst();
    }

}

347.前 K 个高频元素

  1. 小顶堆 大顶堆 都是通过二叉树实现
  2. 堆用于解决 topK 问题
  3. 小顶堆顶部为最小的元素 每次弹出最小元素
  4. 用map统计每个元素频率
  5. 用堆来解决前k个高频的问题 遍历Map<key,value>并存入堆
  6. 当堆size大于k时,pop
  7. 创建一个int[] 数组 倒序 来接堆pop
  8. java 用 PriorityQueue实现优先队列

小顶堆实现

class Solution {
public int[] topKFrequent2(int[] nums, int k) {
        Map<Integer,Integer> map = new HashMap<>();//key为数组元素值,val为对应出现次数
        for(int num:nums){
            map.put(num,map.getOrDefault(num,0)+1);
        }
        //在优先队列中存储二元组(num,cnt),cnt表示元素值num在数组中的出现次数
        //出现次数按从队头到队尾的顺序是从小到大排,出现次数最低的在队头(相当于小顶堆)
        PriorityQueue<int[]> pq = new PriorityQueue<>((pair1,pair2)->pair1[1]-pair2[1]);
        for(Map.Entry<Integer,Integer> entry:map.entrySet()){//小顶堆只需要维持k个元素有序
            if(pq.size()<k){//小顶堆元素个数小于k个时直接加
                pq.add(new int[]{entry.getKey(),entry.getValue()});
            }else{
                if(entry.getValue()>pq.peek()[1]){//当前元素出现次数大于小顶堆的根结点(这k个元素中出现次数最少的那个)
                    pq.poll();//弹出队头(小顶堆的根结点),即把堆里出现次数最少的那个删除,留下的就是出现次数多的了
                    pq.add(new int[]{entry.getKey(),entry.getValue()});
                }
            }
        }
        int[] ans = new int[k];
        for(int i=k-1;i>=0;i--){//依次弹出小顶堆,先弹出的是堆的根,出现次数少,后面弹出的出现次数多
            ans[i] = pq.poll()[0];
        }
        return ans;
    }
}

单调栈、单调队列及优先队列

  1. 单调队列 指队列中元素之间关系具有单调性,而且队首和队尾都可以出队,但是只有队尾可以进行入队操作。其重要作用是找到前n个或者后n个数的最值

  2. 具体操作是:假设单调队列是单调递减队列,假设在插入元素v时,将队列尾部的元素同v比较,如果队列尾部的元素不大于元素v,我们直接删除队尾元素,再将队尾元素与v比较,直至队尾元素比v大,这个时候我们将v插入队尾

  3. 优先队列 是一个队列,优先级高的会先出队列 (堆实现)

  4. 单调栈 也是保持栈内元素单调递增或单调递减。在插入元素时仍需保持栈内元素的单调性。如现有单调栈,其栈内元素为:1 4 5,这时我们将元素3插入单调栈的话;我们需要先将4 5弹出栈在将3入栈,操作之后栈内元素变为1 3。单调栈似乎也可以通过单调队列实现…

总结

通过括号匹配问题、字符串去重问题、逆波兰表达式问题来系统讲解了栈在系统中的应用,以及使用技巧。

通过求滑动窗口最大值,以及前K个高频元素介绍了两种队列:单调队列和优先级队列,

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值