算法训练Day13|堆与优先队列

79 阅读1分钟

150 逆波兰表达式

public int evalRPN(String[] tokens) {
    Deque<Integer> stack = new ArrayDeque<>();
    for (String s : tokens) {
        if ("+".equals(s)) {
            stack.push(stack.pop() + stack.pop());
        } else if ("-".equals(s)) {
            stack.push(-stack.pop() + stack.pop());
        } else if ("*".equals(s)) {
            stack.push(stack.pop() * stack.pop());
        } else if ("/".equals(s)) {
            int temp1 = stack.pop();
            int temp2 = stack.pop();
            stack.push(temp2 / temp1);
        } else {
            stack.push(Integer.valueOf(s));
        }

    }
    return stack.pop();
}

239 滑动窗口的最大值

双向队列

解析

public int[] maxSlidingWindow(int[] nums, int k) {
   int numsLength = nums.length;

   if (nums == null || numsLength < 2) {
       return nums;
   }
   //双端队列 存的是元素位置 且对应的元素从大到小
   Deque<Integer> deque = new LinkedList<>();
   //结果数组
   int[] result = new int[numsLength - k + 1];

   //i是有边界
   for (int i = 0; i < numsLength; i++) {
       //保证队列中的数字从大到小
       //如果右端的数字小则弹出,直到满足需求
       while (!deque.isEmpty() && nums[deque.peekLast()] <= nums[i]) {
           deque.pollLast();
       }
       //添加当前值对应的数组下标
       deque.addLast(i);
       //判断当前队列的队首值是否还在窗口中 i-k的位置刚好是左窗口的左边
       if (deque.peekFirst() <= (i-k)) {
           deque.pollFirst();
       }
       //当窗口长度为k时 保存当前窗口中的最大值
       if (i+1 >= k) {
           result[i+1-k] = nums[deque.peekFirst()];
       }
   }
   return result;
}

347 前K个高频元素

java小顶堆左减右

小顶堆,需要维持整个堆大小为k, 如果堆大小已经为k,那么新来的元素要与堆顶比较, 如果新元素大于堆顶,则将原堆顶移除,新元素入堆

public int[] topKFrequent(int[] nums, int k) {
    Map<Integer, Integer> map = new HashMap<>();
    for (int i : nums) {
        map.put(i, map.getOrDefault(i, 0) + 1);
    }
    //int[]的第一个元素代表数组的值,第二个元素代表了该值出现的次数
    PriorityQueue<int[]> priorityQueue = new PriorityQueue<>((pair1, pair2)-> pair1[1]-pair2[1]);
    for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
        int num = entry.getKey();
        int count = entry.getValue();
        if (priorityQueue.size() >= k) {
            if (priorityQueue.peek()[1] < count) {
                priorityQueue.poll();
                priorityQueue.offer(new int[]{num, count});
            }
        } else {
            priorityQueue.offer(new int[]{num, count});
        }
    }
    int[] result = new int[k];
    for (int i = 0; i < k; i++) {
        result[i] = priorityQueue.poll()[0];
    }

    return result;
}

java大顶堆右减左

大顶堆则简单许多,将所有元素放入堆中, 则最大的在堆顶,最后只需要从堆顶获取k个元素即可

public int[] topKFrequent(int[] nums, int k) {
    Map<Integer, Integer> map = new HashMap<>();
    for (int i : nums) {
        map.put(i, map.getOrDefault(i, 0) + 1);
    }
    //int[]的第一个元素代表数组的值,第二个元素代表了该值出现的次数
    PriorityQueue<int[]> priorityQueue = new PriorityQueue<>((pair1, pair2) -> pair2[1] - pair1[1]);
    for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
        int num = entry.getKey();
        int count = entry.getValue();
        priorityQueue.offer(new int[]{num, count});
    }
    int[] result = new int[k];
    for (int i = 0; i < k; i++) {
        result[i] = priorityQueue.poll()[0];
    }

    return result;
}