leetcode刷题day11|栈与队列Part02(150. 逆波兰表达式求值、239. 滑动窗口最大值、347.前 K 个高频元素)

150. 逆波兰表达式求值

思路:遇到数字则入栈;遇到运算符则取出栈顶两个数字进行计算,并将结果压入栈中。
代码如下:

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

注意:leetcode 内置jdk的问题,不能使用==判断字符串是否相等

239. 滑动窗口最大值

思路:考察队列的应用。维护一个单调非递增队列Deque,存放元素的下标。如果元素的下标小于滑动窗口的范围就poll掉,添加元素时要判断尾端的元素是否小于新加入的元素,true就将小元素remove直到单调队列中的元素大于新加入的元素。
代码如下:

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        Deque<Integer> deque =new ArrayDeque<Integer>();
        int[] res=new int[nums.length-k+1];
        int index=0;
        for(int i=0;i<nums.length;i++){
            if(!deque.isEmpty() && deque.peek()<i-k+1){
                deque.poll();
            }
            
            while(!deque.isEmpty() && nums[deque.peekLast()]<nums[i]){
                deque.removeLast();
            }
            deque.offer(i);

            if(i>=k-1){
                res[index++]=nums[deque.peek()];
            }
        }
        return res;
    }
}

注意:当前k个元素都加进去后开始记录结果。

347.前 K 个高频元素

思路:该题的第一反应就是使用HashMap各个元素出现的次数,但具体如何排序和找到前k个元素就不知道如何去做了。这里比较好的一个解题方法是使用大顶堆和小顶堆来实现。

下面对进行介绍:

Java 中的大顶堆(Max Heap)和小顶堆(Min Heap)是基于二叉堆(Binary Heap)的数据结构。二叉堆是一种特殊的完全二叉树,其中每个父节点的关键字要么大于等于其子节点的关键字(大顶堆),要么小于等于其子节点的关键字(小顶堆)。

  • 大顶堆(Max Heap):在大顶堆中,对于任意节点 i(除了叶子节点),满足以下条件:
    heap[i] >= heap[2i+1] (左子节点)
    heap[i] >= heap[2
    i+2] (右子节点)
  • 小顶堆(Min Heap):在小顶堆中,对于任意节点 i(除了叶子节点),满足以下条件:
    heap[i] <= heap[2i+1] (左子节点)
    heap[i] <= heap[2
    i+2] (右子节点)

在java中,大顶堆和小顶堆可以通过继承 PriorityQueue 类或自定义类来实现。PriorityQueue 默认是一个小顶堆,可以通过自定义比较器来实现大顶堆。

PriorityQueue介绍

PriorityQueue 是 Java 集合框架中的一个类,它实现了 Queue 接口,并提供了基于优先级队列的数据结构。优先级队列中每个元素都有一个优先级,通常具有较高优先级的元素会比具有较低优先级的元素更早被处理。

常用方法

  • offer(E e):将元素添加到队列中,如果成功添加则返回 true。
  • poll():检索并移除队列头部的元素,如果队列为空则返回 null。
  • peek():检索但不移除队列头部的元素,如果队列为空则返回 null。
  • isEmpty():如果队列为空则返回 true。
  • size():返回队列中的元素数量。
  • clear():移除队列中的所有元素。

构造函数

  • PriorityQueue():创建一个初始容量为 11 的空优先队列。
  • PriorityQueue(int initialCapacity):创建一个具有指定初始容量的空优先队列。
  • PriorityQueue(int initialCapacity, Comparator<? super E> comparator):创建一个带有指定比较器的优先队列。
  • PriorityQueue(Collection<? extends E> c):创建一个包含指定集合中的元素的优先队列。
  • PriorityQueue(PriorityQueue q):创建一个包含指定优先队列中元素的新优先队列。

示例代码

  • 使用自然排序
import java.util.PriorityQueue;

public class PriorityQueueExample {
    public static void main(String[] args) {
        // 创建一个 PriorityQueue,元素为 Integer 类型
        PriorityQueue<Integer> pq = new PriorityQueue<>();
        
        pq.offer(5);
        pq.offer(1);
        pq.offer(3);
        pq.offer(4);
        pq.offer(2);
        
        // 检索并移除队列头部的元素
        while (!pq.isEmpty()) {
            System.out.println(pq.poll());  // 输出 1, 2, 3, 4, 5
        }
    }
}
  • 使用自定义比较器
import java.util.Comparator;
import java.util.PriorityQueue;

public class PriorityQueueExample {
    public static void main(String[] args) {
        // 创建一个 PriorityQueue,使用自定义比较器实现最大堆
        PriorityQueue<Integer> pq = new PriorityQueue<>(Comparator.reverseOrder());
        
        pq.offer(5);
        pq.offer(1);
        pq.offer(3);
        pq.offer(4);
        pq.offer(2);
        
        // 检索并移除队列头部的元素
        while (!pq.isEmpty()) {
            System.out.println(pq.poll());  // 输出 5, 4, 3, 2, 1
        }
    }
}
  • 使用整数数组的例子

如果你需要使用整数数组作为优先队列的元素,并根据数组的某个元素进行排序,可以使用下面的代码示例:

import java.util.Comparator;
import java.util.PriorityQueue;

public class PriorityQueueIntArrayExample {
    public static void main(String[] args) {
        // 创建一个 PriorityQueue,元素为 int[] 类型,根据数组中的第二个元素进行排序
        PriorityQueue<int[]> pq = new PriorityQueue<>((o1, o2) -> o1[1] - o2[1]);
        
        pq.offer(new int[]{1, 10});
        pq.offer(new int[]{2, 5});
        pq.offer(new int[]{3, 15});
        pq.offer(new int[]{4, 1});
        
        // 检索并移除队列头部的元素
        while (!pq.isEmpty()) {
            int[] arr = pq.poll();
            System.out.println("[" + arr[0] + ", " + arr[1] + "]");
        }
    }
}

了解了以上内容,就可以使用小顶堆来解决本题了。
代码如下:

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        HashMap<Integer,Integer> map =new HashMap<>();
        PriorityQueue<int[]> pq=new PriorityQueue<>((o1,o2) -> o1[1]-o2[1]);
        int[] res= new int[k];
        for(int num:nums){
            map.put(num,map.getOrDefault(num,0)+1);
        }
        for(var x : map.entrySet()){
            int[] temp=new int[2];
            temp[0]=x.getKey();
            temp[1]=x.getValue();
            pq.offer(temp);
            if(pq.size()>k){
                pq.poll();
            }
        }
        for(int i=0;i<k;i++){
            res[i]=pq.poll()[0];
        }
        return res;
    }
}
  • 19
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值