LeetCode·每日一题·2208. 将数组和减半的最少操作次数·优先队列

作者:小迅
链接: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)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

猜你喜欢

转载自blog.csdn.net/m0_64560763/article/details/131912698