1558. 得到目标数组的最少函数调用次数
大约 4 分钟
---
1558. 得到目标数组的最少函数调用次数
- 标签:贪心、位运算、数组
- 难度:中等
题目链接
题目大意
描述:初始数组全为 ,可以执行两种操作:
- 将任意一个元素加 。
- 将所有元素乘以 。
给定目标数组 。
要求:返回将初始数组变为 所需的最少操作次数。
说明:
- 。
- 。
示例:
- 示例 1:
输入:nums = [1,5]
输出:5
解释:给第二个数加 1 :[0, 0] 变成 [0, 1] (1 次操作)。
将所有数字乘以 2 :[0, 1] -> [0, 2] -> [0, 4] (2 次操作)。
给两个数字都加 1 :[0, 4] -> [1, 4] -> [1, 5] (2 次操作)。
总操作次数为:1 + 2 + 2 = 5 。- 示例 2:
输入:nums = [2,2]
输出:3
解释:给两个数字都加 1 :[0, 0] -> [0, 1] -> [1, 1] (2 次操作)。
将所有数字乘以 2 : [1, 1] -> [2, 2] (1 次操作)。
总操作次数为: 2 + 1 = 3 。解题思路
思路 1:位运算 + 贪心
1. 核心思想
将所有数组元素视为二进制数。操作 (加 )负责将某些位从 变 。操作 (乘以 )负责左移操作。
考虑整体:
- 每个元素需要若干次加 操作来设置二进制位。
- 所有元素共享乘 操作(所有元素同时乘 )。
对于每个 ,看其二进制表示:
- 执行加 的次数 = 二进制中 的个数(设置每个 位需要一次加 )。
- 执行乘 的次数 = 二进制最高位的位置(每次乘 对应左移一位)。
全局:
- 总加 次数 = 所有元素二进制中 的个数之和。
- 总乘 次数 = 所有元素中最大二进制位长度减 (因为初始全 ,乘 从 开始有效)。
2. 具体步骤
第 1 步:初始化 ,。
第 2 步:遍历每个 :
- (二进制中 的个数)。
- (最高位位置)。
第 3 步:返回 。如果所有元素为 ,,返回 。
3. 举例说明
以 为例:
- 的二进制
1: 个 ,最高位 。 - 的二进制
101: 个 ,最高位 。
,。
总次数 。
操作过程:
- → (位置 加 )
- →
- →
- → (位置 加 )
- →
不对,目标是 ...
等等,让我重新思考过程:
初始
- 位置 加 →
- 位置 加 →
- 全部乘 →
- 位置 加 →
- 全部乘 →
不对,乘 是所有同时。但这不对。
实际上,我们可以先全部加 再乘 :
- 位置 加 →
- 全部乘 →
- 位置 加 →
- 全部乘 →
- 位置 加 →
...还是不对。
目标 。 的二进制是 101,表示需要 和 。
换个思路:?
不对。让我给出一个可行的方案:
- pos1 →
- →
- →
- pos1 →
- pos0 →
共 步: 次加 , 次乘 。符合公式。
4. 关键理解
- 每次乘 是所有元素一起乘 。因此全局乘 的次数由最大的那个数的二进制位数决定。
- 每个元素中的每个 都需要一次加 操作来设置。
思路 1:代码
class Solution:
def minOperations(self, nums: List[int]) -> int:
add = 0
max_bit = 0
for x in nums:
add += x.bit_count()
max_bit = max(max_bit, x.bit_length() - 1)
return add + max(max_bit, 0)思路 1:复杂度分析
- 时间复杂度:。
- 空间复杂度:。