优先队列是队列数据结构实现,其中根据优先级处理对象,在优先队列中,添加的对象根据其优先级,默认情况下,优先级由对象的自然顺序决定的。队列构建时提供的比较器可以覆盖默认优先级。
优先队列就是一个堆,它可以维护一个集合的最大值(或最小值),可以在很优秀的时间复杂度(log级别)内进行查询,插入push和删除pop.
例题
问题描述
小雷拿到了一个数组,他计算了一下数组的和,感觉和也太大了,所以他准备对数组中的每个元素进行取余操作,让数组的和变得小一点。
具体来说,给定一个数组 a ,共有 q 次操作,每次操作给定一个值 x ,对数组的每个元素对 x 进行一次取模,输出每次操作后,数组所有元素的和。
输入格式
第一行有两个整数n,q ,代表数组 a 的元素个数和操作个数。
第二行输入 n 个元素,代表数组 a 。
第三行输入 q 个元素,代表 q 次操作。
输出格式
输出仅一行,包含 q 个由空格分开的整数,第 i 个整数代表第 qi 次操作后的结果。
样例输入
5 3
1 2 3 4 5
4 2 1
样例输出
7 3 0
说明
初始数组为 [1,2,3,4,5]
,和为 15 。
进行第一次 x 为 4 的取模操作后,数组变为 [1,2,3,0,1]
,和为 7 。
进行第二次 x 为 2 的取模操作后,数组变为 [1,0,1,0,1]
,和为 3 。
进行第三次 x 为 1 的取模操作后,数组变为 [0,0,0,0,0]
,和为 0。
构建数值从大到小的优先序列
每次比较对头和x的大小关系,如果队头大于x,把对头弹出来,将队头对x取模的值压入队列中。
代码
package dui;
import java.util.*;
public class chapter1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scan=new Scanner(System.in);
int n=scan.nextInt();
int q=scan.nextInt();
long sum=0;
PriorityQueue<Integer> queue=new PriorityQueue<>((o1,o2)->o2-o1);
for(int i=0;i<n;i++) {
int x=scan.nextInt();
queue.add(x);
sum+=x;
}
while(q-->0) {
//q次操作
int k=scan.nextInt();
while(!queue.isEmpty()&&queue.peek()>=k) {
//判断队列是否为空,以及对头中的元素大于我们当前要取余的值
int x=queue.poll();//弹出(一直弹出比k大的数)
sum-=x;
queue.add(x%k);//对k取余后的值添加到队列中
sum+=x%k;
}
System.out.print(sum+" ");//每次需要输出sum
}
}
}