Problem: 2208. 将数组和减半的最少操作次数
思路
题目说要最少操作次数,也就是说我们需要在每次操作时的收益最大,即每次都是对最大的数进行减半操作从而实现局部最优,进而做到全局最优。这里我们就很容易想到了 贪心 + 优先队列 的思想来解决这道题
解题方法
- 先构建一个大根堆,同时原数组的和
- 算出一半的数组和,也就是我们的贪心临界点
- 对构建的大根堆进行循环减半操作,每次循环时用
count
记录次数
复杂度
时间复杂度:
这里用了两个循环,所以时间复杂度为 O ( n ) O(n) O(n)
空间复杂度:
创建了一个大根堆, 空间复杂度为 O ( n ) O(n) O(n)
C++代码
class Solution {
public:
int halveArray(vector<int>& nums) {
priority_queue<double> heap; // 构建一个大根堆
double sum = 0.0; // 计算数组和
for(auto& x : nums) { // 将元素依次插入大根堆中
sum += x;
heap.push(x);
}
sum /= 2.0; // 计算数组的一半和
int count = 0; // 创建变量记录操作次数
while(sum > 0) { // 如果 sum > 0 循环就继续
double t = heap.top() / 2.0; // 对最大的元素进行减半操作(局部最优进而达到全局最优)
heap.pop(); // 删除堆顶元素
sum -= t;
count++; // 操作次数 + 1
heap.push(t); // 将减半后的元素重新插入到大根堆中
}
return count; // 返回最后结果
}
};
Java代码
class Solution {
public int halveArray(int[] nums) {
// 创建⼀个⼤根堆
PriorityQueue<Double> heap = new PriorityQueue<>((a, b) -> b.compareTo(a));
double sum = 0.0;
for (int x : nums) // 把元素都丢进堆中,并求出累加和
{
heap.offer((double) x);
sum += x;
}
sum /= 2.0; // 先算出⽬标和
int count = 0;
while (sum > 0) // 依次取出堆顶元素减半,直到减到之前的⼀半以下
{
double t = heap.poll() / 2.0;
sum -= t;
count++;
heap.offer(t);
}
return count;
}
}