给你一个正整数数组 nums
。每一次操作中,你可以从 nums
中选择 任意 一个数并将它减小到 恰好 一半。(注意,在后续操作中你可以对减半过的数继续执行操作)
请你返回将 nums
数组和 至少 减少一半的 最少 操作数。
看到这里的时候,我自己想的就是用贪心算法,每次选中数组中的最大值,再将最大值放回数组,然后搞了一堆,写完提交肯定是超出编译时间的,看了别人的发现可以用优先队列,然后自己又去把队列的知识恶补了一下。
首先是我们要用到的优先队列,直接创建优先队列的话,队列是按顺序排列的。
PriorityQueue<> pq = new PriorityQueue<>();
但是我们要找最大值,又因为PriorityQueue中有一个取顶部值的方法poll(),所以我们给它换一个排序方法。
PriorityQueue<> pq = new PriorityQueue<>((a,b)->b.compareTo(a);
说一下相关要用的方法
poll(),取顶部值,并删除顶部元素,队列中没有元素返回null。
offer(E e),插入指定元素,不能为null。
class Solution {
public int halveArray(int[] nums) {
// PriorityQueue本身是顺序排列,下面我们要用的是最大值,所以直接把队列弄成倒序
PriorityQueue<Double> pq = new PriorityQueue<Double>((a,b)->b.compareTo(a));
int count = 0;
double sum = 0; // 这里sum的数据类型一定要是double,因为sum和sum1在比较的时候有可能出错
for(int num:nums){
sum += num;
//把数组中的元素添加到优先队列中
pq.offer((double)num);
}
double sum1 = 0.0;
//当被减去值的总和sum1大于等于原队列总和时,退出循环
while(sum1<sum/2){
//取到并删除堆顶元素
double n = pq.poll();
sum1 += n/2;
//将元素减半之后重新放入队列
pq.offer(n/2);
count++;
}
return count;
}
}