算法—(5)栈与队列

一、匹配括号

1.题目描述:给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回 滑动窗口中的最大值 

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置                最大值
---------------               -----
[1  3  -1] -3  5  3  6  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

2.方法采用:由上述图可知,每次滑动窗口的移动都会造成一个数据的移除和一个数据的加入,我们需要处理的数据其实就是对移除数据和加入数据的处理,一般这种情况采用队和栈进行管理较好,因为队和栈的出入与这个操作很相似。

3.代码:

class Solution {

    public int[] maxSlidingWindow(int[] nums, int k) {

      Deque<Integer> deque = new LinkedList<Integer>();

     for(int i = 0; i < k; i++){

         //先将前k个入队

         while(!deque.isEmpty() && nums[i] > deque.peekLast()){

             //需要先判断队列是否为空,当需要进队的最大时候,队内为空的时候所以需要判断条件为空

         deque.pollLast();

         }

         deque.addLast(nums[i]);

     }

     int temp = nums.length - k + 1;//注意返回的数组长度

     int result[] = new int[temp];

     result[0] = deque.peekFirst();

     int j = 1;

     for(int i = k; i < nums.length; i++){

         

         if( nums[i-k] == deque.peekFirst()){

             //将需要退栈的与最大的数对比,如果相等就需要退栈,否者就不需要操作。

             deque.pollFirst();

         }

         while(!deque.isEmpty() && nums[i] > deque.peekLast() ){

             //如果大于则需要将里面的退栈,直到不大于为止进栈,这样就是一直保持着大小顺序,可能会思考退栈的元素会不会造成影响,肯定不会,因为新进展的元素肯定比前面的元素要大并且退栈也比他们晚,所以不影响。

         deque.pollLast();

         }

         deque.addLast(nums[i]);

         result[j] = deque.peekFirst();

         j++;

     }

     return result;

    }

}

4.具体思路

1.首先需要判断滑动窗口的最大值,如果需要每次都要求一遍最大值肯定不好,所以采用一个单调队列比较好,每次取最大值都很简单。

2.取最大值的问题解决了,还剩下加入和移除的问题,加入队列时,因为要维持整个队列的单调性,每次从队列最小数据端开始加入,如果数据小于队列中的数据,直接加入在尾部就好了。如果大于队列的数据,就一直要将数据中的队列出队,知道插入该数据。注意!!!可能有疑问,把前面那些数据都出队后,那如果后面把较大的数据都出列了,该数据为最大元素怎么办但是已经出队了怎么办。其实这很好解释,出队该元素的原理是因为你需要插入一个比你大的数据并且该数据在数组中还在你后面,滑动窗口把你滑出去了该元素都不可能滑动出去,所以不可能运用到该元素。

3.移除队列的问题:首先得判断滑动窗口中需要移除的元素是否与队列中的最大元素相同,如果相同的话肯定得将这个元素出队,否则就不需要处理出队。注意!!!可能有疑问,如果不处理该数据入队的话,如果后面把较大的数据都出列了,该数据为最大元素怎么办但是他本应该已经出队了怎么办。当需要被滑出的数据就是队列最大值时,我们应该清楚这时候根据队列入队原则,这时候队列中的的数据肯定都是最大值后面的数据。

4.根本的点:如果需要出队,那么队内的元素都是数组后面的元素。

二、前k个高频元素(主要是优先级队列的使用)

1.题目描述:给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

2.思路分析:需要解决2个问题,频率的统计以及排序找出前k高的元素。统计频率我们很容易想到map,数据中找出前k大的数据我们很容易想到堆。找的时候前k大的数据的话,那么堆最好是用小顶堆,每次只需要维护k个元素的堆,每次将最小的元素出堆,这样遍历完数据就只剩下最大的10个数据了。

class Solution {

    public int[] topKFrequent(int[] nums, int k) {

        HashMap<Integer,Integer> map = new HashMap();

        for(int i = 0; i < nums.length;i++){

            if(map.containsKey(nums[i])){

               int temp = map.get(nums[i]) + 1;

               map.put(nums[i],temp);

            }

            else map.put(nums[i],1);

        }//使用map来统计每个数据的出现频率

         PriorityQueue<Integer> pq = new PriorityQueue<>(new Comparator<Integer>() {

 //使用java中提供的优先级队列,它的底层实现就是采用堆,这里因为入队的数据为数据,而排序的依据是频率,所以这里的比较规则需要改变,需要重写Comparator方法来改变规则。

            @Override

            public int compare(Integer integer, Integer t1) {

                return map.get(integer) - map.get(t1);

            }

        });

        for (Integer key: map.keySet()) {

            pq.offer(key);

            if(pq.size() > k){

                pq.poll();

            }

           }

           int result[] = new int[k];

        for(int j = k-1; j >= 0;j--){

            result[j] = pq.poll();

        }

        return result;

    }

}

3.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值