证明:假设某一种做法(该做法操作次数最小)的某一步操作没有选择对最大值 x 进行操作,而是选择对 y 进行操作,那么有两种情况: 1.后续的操作都没有选择对 x 进行操作,那么我们将后续(包括当前操作)所有对 y 的操作替换成对 x 的操作,操作次数不变; 2.后续的某一步操作选择对 x 进行操作,那么我们可以交换这两步操作,操作次数不变。
将数组所有元素都放入一个浮点数优先队列(最大堆)中,使用 sum 记录初始数组和,sum}_2 记录减少和,当 sum}_2 \lt \dfrac{\textit{sum} }{2 时,重复以下步骤:
从优先队列中取出最大元素 x;
令 sum}_2 = \textit{sum}_2 + \dfrac{x}{2;
将 \dfrac{x}{2 放入优先队列中。
返回执行步骤次数即可。
[sol1-C++]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
classSolution { public: inthalveArray(vector<int>& nums){ priority_queue<double> pq(nums.begin(), nums.end()); int res = 0; double sum = accumulate(nums.begin(), nums.end(), 0.0), sum2 = 0.0; while (sum2 < sum / 2) { double x = pq.top(); pq.pop(); sum2 += x / 2; pq.push(x / 2); res++; } return res; } };
func(pq *PriorityQueue) Pop() any { old, n := *pq, len(*pq) x := old[n - 1] *pq = old[0 : n-1] return x }
funchalveArray(nums []int)int { pq := &PriorityQueue{} sum, sum2 := 0.0, 0.0 for _, x := range nums { heap.Push(pq, float64(x)) sum += float64(x) } res := 0 for sum2 < sum / 2 { x := heap.Pop(pq).(float64) sum2 += x / 2 heap.Push(pq, x / 2) res++ } return res }
复杂度分析
时间复杂度:O(n \log n),其中 n 是数组 nums 的长度。将数组和减半最多不超过 n 次操作,每次操作需要 O(\log n)。