Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
每日刷题第71天 2021.03.21
2208. 将数组和减半的最少操作次数
- leetcode原题链接:leetcode-cn.com/problems/mi…
- 难度:中等
- 方法:dfs+二分
题目描述
- 给你一个正整数数组
nums
。每一次操作中,你可以从nums
中选择任意一个数并将它减小到恰好一半。(注意,在后续操作中你可以对减半过的数继续执行操作) - 请你返回将
nums
数组和至少减少一半的最少操作数。
示例
- 示例1
输入:nums = [5,19,8,1]
输出:3
解释:初始 nums 的和为 5 + 19 + 8 + 1 = 33 。
以下是将数组和减少至少一半的一种方法:
选择数字 19 并减小为 9.5 。
选择数字 9.5 并减小为 4.75 。
选择数字 8 并减小为 4 。
最终数组为 [5, 4.75, 4, 1] ,和为 5 + 4.75 + 4 + 1 = 14.75 。
nums 的和减小了 33 - 14.75 = 18.25 ,减小的部分超过了初始数组和的一半,18.25 >= 33/2 = 16.5 。
我们需要 3 个操作实现题目要求,所以返回 3 。
可以证明,无法通过少于 3 个操作使数组和减少至少一半。
复制代码
- 示例2
输入:nums = [3,8,20]
输出:3
解释:初始 nums 的和为 3 + 8 + 20 = 31 。
以下是将数组和减少至少一半的一种方法:
选择数字 20 并减小为 10 。
选择数字 10 并减小为 5 。
选择数字 3 并减小为 1.5 。
最终数组为 [1.5, 8, 5] ,和为 1.5 + 8 + 5 = 14.5 。
nums 的和减小了 31 - 14.5 = 16.5 ,减小的部分超过了初始数组和的一半, 16.5 >= 31/2 = 16.5 。
我们需要 3 个操作实现题目要求,所以返回 3 。
可以证明,无法通过少于 3 个操作使数组和减少至少一半。
复制代码
提示
1 <= nums.length <= 105
1 <= nums[i] <= 107
思路总结
- 本题主要考察的点:优先队列的使用
PriorityQueue
- 思路:根据题意,需要找到最少操作数,使数组和减少至一半。
- 那么每次就需要找到当前的数组中最大的值,将其取一半,才能保证用最少的操作数使数组和减少一半
具体步骤
- 将原数组求和,记为
total
,数组和的一半记为half
- 将数组中所有的元素压入优先队列中,每次取队列中的数,一定是当前数组中最大的数。拿到当前最大的数,将其减半之后,再放入到优先队列中。
- 以此循环,就可以保证小于
half
的时候,一定是最小的操作数。
AC
代码
js
是没有内置的PriorityQueue
优先队列的,但是Leetcode
有内置的函数MaxPriorityQueue
var halveArray = function(nums) {
// 数组的求和函数,初始值为0
let total = nums.reduce((cur, next) => cur + next, 0)
const half = total / 2
const queue = new MaxPriorityQueue()
for (const num of nums) {
queue.enqueue(num, num)
}
let ans = 0
while (total > half) {
let { element } = queue.dequeue()
ans ++
element /= 2
total -= element
queue.enqueue(element, element)
}
return ans
};
复制代码
总结
- 单纯考优先队列使用的题目,记住几个操作方法
new MaxPriorityQueue()
创建队列queue.enqueue()
入队queue.dequeue()
出队