作者:小迅
链接:https://leetcode.cn/problems/minimum-operations-to-halve-array-sum/solutions/2357852/you-xian-dui-lie-zhu-shi-chao-ji-xiang-x-805n/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
题目
示例
思路
题意 -> 给定一个数组,每次操作可以将任意一个元素值减半,返回最小操作次数,使得数组元素和为原数组和的一半。
贪心思想,要使得操作次数尽可能小,那么每次减少时肯定要选择最大值减,这样才能使得每一步发挥到最大效益。
那么怎么样才能每次都选择最大值呢?
- 题意只要求返回操作次数,并不关心数组内容,那么可以对数组进行排序,每次只需要取边界就可以拿到最大值。
每次取完一个元素减半后,再对数组排序,重复上述操作。
其实到这里,整体思路已经确定,但是不同的排序算法,时间复杂度是不一样,需要选择一个时间复杂度小的排序,而我们每一次只改变最顶端的一个元素大小,其他元素还是有序,那么使用堆排序就很不错,也就是优先队列。
代码注释超级详细
代码
// 堆排序:(最大堆,有序区)。从堆顶把根卸出来放在有序区之前,再恢复堆。
void max_heapify(float arr[], int start, int end) {
//建立父节点指标和子节点指标
int dad = start;
int son = dad * 2 + 1;
while (son <= end) { //若子节点在范围内才做比较
if (son + 1 <= end && arr[son] < arr[son + 1]) //先比较两个子节点指标,选择最大的
son++;
if (arr[dad] >= arr[son]) //如果父节点大于子节点代表调整完成,直接跳出函数
return;
else { //否则交换父子内容再继续子节点与孙节点比较
float temp = arr[dad];
arr[dad] = arr[son];
arr[son] = temp;
dad = son;
son = dad * 2 + 1;
}
}
}
int halveArray(int* nums, int numsSize){
double sum = 0;
float num[numsSize];
for (int i = 0; i < numsSize; ++i) {//累和并初始化堆
sum += nums[i];
num[i] = nums[i];
}
for (int i = numsSize / 2 - 1; i >= 0; i--)//调整堆
//调整每一个父节点下的子节点大小
max_heapify(num, i, numsSize - 1);
double temp = sum;
int count = 0;
while (sum < temp * 2) {//枚举操作数
max_heapify(num, 0, numsSize-1);//调整和取数没有先后顺序,都可以
num[0] /= 2;//取最大值操作
temp -= num[0];
++count;
}
return count;
}
作者:小迅
链接:https://leetcode.cn/problems/minimum-operations-to-halve-array-sum/solutions/2357852/you-xian-dui-lie-zhu-shi-chao-ji-xiang-x-805n/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。