代码随想录算法训练营day13|栈和队列

  • 239. 滑动窗口最大值
    暴力算法:数组从前到后遍历,下标每次移动都比较一次窗口内的所有元素得出最大值,时间复杂度显然为n*k。
  • 很显然,用暴力来做这道题目显然是不符合困难的难度。虽然这题被编排在了栈和队列的章节里面,但是我实在是没有头绪。
  • 看了代码随想录提供的思路以及carl视频所说的单调列表的思想,对这题有了初步的了解。由于鄙人数据结构的基础并不是很好,在视频中提到的大顶堆和小顶堆我还特意看了两个视频补了一下课,大顶堆和小顶堆的方法会改变窗口内数组的顺序,因此窗口滑动的时候难以进行窗口内数据的移除。
  • 单调队列的思想,就是要始终保持窗口内最大的元素在队头,同时不能改变元素的顺序。在个人的理解中,其实就是将不可能作为滑动窗口中最大值的数提前出队。比如,在本题的示例1中,1是第一个入队的元素,当3将要入队的时候,因为3比1大,因此在3入队后1不可能作为最大值,所以为了让滑动窗口的最大值始终在队头,元素1提前出队。此时,并没有改变原来数组的排列顺序,只是我们让不可能作为最大值输出的数提前出队而已,3依然在5入队的时候弹出。那么代码的逻辑已经很清晰了,元素入队时弹出前面所有小于它的数,每次需要得到滑动窗口最大值时则获取队头的元素,由于我们为了让最大值始终保持在队头,提前弹出了较小的元素,因此不是每次滑动窗口移动时,队列中的队头都要弹出,而是应该队列满了再进行队头元素的弹出。
    class MyQueue{
        Deque<Integer> deque=new LinkedList<>();
        void add(int val){
            while(!deque.isEmpty()&&val>deque.getLast())
                deque.removeLast();
            deque.addLast(val);
        }
        void pop(int val){
            if(!deque.isEmpty()&&val==peek())
                deque.poll();
        }
        int peek(){
            return deque.peek();
        }
    }
    class Solution {
        public int[] maxSlidingWindow(int[] nums, int k) {
            
            MyQueue queue=new MyQueue();//创建自定义的单调列表
            //先把窗口填满
            for(int i=0;i<k;i++){
                queue.add(nums[i]);
            }
            int[] result=new int[nums.length-k+1];
            //开始进行窗口的移动以及填充最大值数组
           
            int num=0;
            result[num++]=queue.peek();
            for(int i=k;i<nums.length;i++){
                //窗口滑动,队头元素弹出
                queue.pop(nums[i-k]);
                //窗口滑动,插入队尾元素
                queue.add(nums[i]);
                //记录新窗口中最大元素
                result[num++]=queue.peek();
            }
            return result;
        }
        
    }

  • 347.前 K 个高频元素
    第一步,要先用hashmap将元素和出现的次数记录下来。
    第二步就是要求出hashmap中前k个最大value。
    可以将hashmap中的value进行排序后,再用getKey方法进行记录,此时的时间复杂度应该为快速排序的时间复杂度n*logn。但是这样的时间复杂度不满足题目中对时间复杂度的要求
  • 更优的解法应该是采用大顶堆或者小顶堆的方法,大顶堆的数据结构完全符合题目的需求,大顶堆中,栈顶一直是堆中元素的最大值,用value构造大顶堆,只需要弹出堆顶元素k次即可,由于大顶堆的数据结构为二叉树,每次弹出后重新形成大顶堆的时间复杂度为logn,因此最终的时间复杂度为klogn。
  • class Solution {
        public int[] topKFrequent(int[] nums, int k) { 
            Map<Integer,Integer> map=new HashMap<Integer,Integer>();
            //遍历数组构造map
            for(int i=0;i<nums.length;i++){
                map.put(nums[i],map.getOrDefault(nums[i],0)+1);
            }
    		//构造大根堆	
    		PriorityQueue<int[]>pq=new PriorityQueue<>((pair1,pair2)->pair2[1]-pair1[1] );
    
    		for (Map.Entry<Integer, Integer> entry: map.entrySet() ) {
    			pq.add(new int[]{entry.getKey(),entry.getValue()});
    		}
    		
    		int[] ans=new int[k];
    		//大根堆依次弹出前k个最大元素
    		for(int i=0;i<ans.length;i++)
    			ans[i]=pq.poll()[0];
    		return ans;
            
        }
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值