【刷题笔记05】-栈与队列

刷题笔记系列

【刷题笔记01】- 数组
【刷题笔记02】-链表
【刷题笔记03 -哈希表】


1、用栈实现队列

  • 思路:
    栈是先进后出,队列是先进先出,也就是说相同的顺序进入,出来结果是反的。
    用栈实现队列那势必需要像交换值一样,有个中间容器暂存数据。
    用两个栈实现队列,一个管理入栈,一个管理出栈。
  • 代码
class MyQueue {
    Stack<Integer> stackIn;
    Stack<Integer> stackOut;
    public MyQueue() {
        stackIn = new Stack();
        stackOut = new Stack();
    }    
    public void push(int x) {
        stackIn.push(x);
    }   
    public int pop() {
        pushToOut();
        return stackOut.pop();
    }   
    public int peek() {
        pushToOut();
        return stackOut.peek();
    } 
    private void pushToOut(){
        if(stackOut.empty()){
            while(!stackIn.empty()){
                stackOut.push(stackIn.pop());
            }
        }
    }
    public boolean empty() {
        return stackIn.empty() && stackOut.empty();
    }
}

2、用队列实现栈

  • 思路:
    和栈实现队列类似,在出栈、找栈顶元素做改变顺序的处理就行。
    不过用队列实现栈 也可以一个容器就行。
    因为队列两头都是通的,用length记录队列长度,就可以区分旧元素和新入元素,以此来管理标识轮次(层次遍历迭代法用队列实现时,也有这种做法)
  • 代码
class MyStack {
    ArrayDeque<Integer> mQueue;
    int length;
    public MyStack() {
        mQueue = new ArrayDeque<>();
        length = 0;
    }
    
    public void push(int x) {
        mQueue.add(x);
        length++;
    }
    
    public int pop() {
        for(int i = 0;i<length-1;i++){
            mQueue.add(mQueue.poll());
        }
        length--;
        return mQueue.poll();
    }
    
    public int top() {
        for(int i = 0;i<length-1;i++){
            mQueue.add(mQueue.poll());
        }
        int result = mQueue.peek();
        mQueue.add(mQueue.poll());
        return result;
    }
    
    public boolean empty() {
        return mQueue.isEmpty();
    }
}

3、前k个高频元素

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

  • 思路:
    先遍历一遍统计元素和对应出现频次存入map
    后面的处理有两种思路:
    ① 用桶排序 对出现频次进行处理(index为出现频次,value为出现频次为该频次的元素列表);倒序从桶排序结果取 k 个
    ② 利用优先级队列,将频次和对应元素存入,以频次为比较依据;最后从优先级队列中取出 k 个
  • 代码
    桶排序写法
    public int[] topKFrequent(int[] nums, int k) {
        HashMap<Integer,Integer> map = new HashMap<>();
        for(int n:nums){
           map.put(n,map.getOrDefault(n,0)+1);
       }
        List<Integer>[] frelists = new List[nums.length + 1];
        for(int key : map.keySet()){
            int i = map.get(key);
            if(frelists[i] == null){
                frelists[i] = new ArrayList();
            }
            frelists[i].add(key);
        }

        List<Integer> res = new ArrayList<>();
        for(int i = nums.length; i >= 0 && res.size() < k ;i--){
            if(frelists[i]==null)
                continue;
            res.addAll(frelists[i]);
        }
        
        return res.stream().mapToInt(Integer::intValue).toArray();
    }

优先级队列写法

    public int[] topKFrequent(int[] nums, int k) {
        HashMap<Integer,Integer> map = new HashMap<>();
        int[] result = new int[k];
        for(int n:nums){
           map.put(n,map.getOrDefault(n,0)+1);
       }
        PriorityQueue<int[]> pq = new PriorityQueue<int[]>(new Comparator<int[]>() {
            public int compare(int[] pair1, int[] pair2) {
                return pair2[0] - pair1[0];
            }
        });
        for(int key : map.keySet()){
            pq.offer(new int[]{map.get(key),key});
        }
        while(k-- > 0){
            result[k] = pq.poll()[1];
        }
        return result;
    }

4、滑动窗口最大值

  • 思路:
    优先队列存储滑动窗口最大值,滑动过程将index不符合的值出队,将最大值存入结果集
  • 代码:
    public int[] maxSlidingWindow(int[] nums, int k) {
        int[] result = new int[nums.length - k + 1];
        PriorityQueue<int[]> pq = new PriorityQueue<int[]>(new Comparator<int[]>() {
            public int compare(int[] pair1, int[] pair2) {
                return pair1[0] != pair2[0] ? pair2[0] - pair1[0] : pair2[1] - pair1[1];
            }
        });
        for (int i = 0; i < k; ++i) {
            pq.offer(new int[]{nums[i], i});
        }
        result[0] = pq.peek()[0];
        for (int i = k; i < nums.length; i++){
            pq.offer(new int[]{nums[i], i});
            while(pq.peek()[1] <= i - k){
                pq.poll();
            }
            result[i - k + 1] = pq.peek()[0];
        }
        return result;
    }

总结

  • 边界想不清楚就带值进去算

TODO:

各种类型的队列的放入、取出API以及相应特性
LinkedList的add方法和push方法的区别

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值