leetcode1558. 得到目标数组的最少函数调用次数
给你一个与 nums
大小相同且初始值全为 0 的数组 arr
,请你调用以上函数得到整数数组 nums
。
请你返回将 arr
变成 nums
的最少函数调用次数。
答案保证在 32 位有符号整数以内。
示例 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 。
示例 3:
输入:nums = [4,2,5]
输出:6
解释:(初始)[0,0,0] -> [1,0,0] -> [1,0,1] -> [2,0,2] -> [2,1,2] -> [4,2,4] -> [4,2,5] (nums 数组)。
示例 4:
输入:nums = [3,2,2,4]
输出:7
示例 5:
输入:nums = [2,4,8,16]
输出:8
提示:
1 <= nums.length <= 10^5
0 <= nums[i] <= 10^9
方法:模拟+位运算
思路:
分析这个函数可知,这个函数每次操作可以选择两种,一种是将数组中某个数加1,另一种是将数组中所有数×2。
因此,我们可以知道,×2的操作是针对数组中所有数字的,因此可以共享,即我们算出数组中每个数需要做乘法的次数,这些次数中最大的次数即为我们需要的乘法次数(对于那些需要乘法次数小于这个最大次数的数字,可以在这个最大数字的剩余乘法次数与它需要的乘法次数相等时,再将这个数从0变换到1再开始进行后续的乘法,这样它们可以同时达到结果)。
由于加法是对每个数字的,因此我们计算的每个数字需要的加法次数需要累加。
因此最后的答案就是总的加法次数+最大乘法次数。
对于每个数字,我们如何计算需要的乘法和加法次数呢?假设数字为n,我们应该自顶向下递归计算:
- 如果n为偶数,那么它应该是乘2得到的,因此乘法次数+1,n=n/2,继续递归。
- 如果n是奇数,那么它应该是加1得到的,因此加法次数+1,n=n-1,继续递归。
- 最后算出加法和乘法的次数。
对于上面的过程,我们可以使用位运算的方法来简化。首先我们知道,对某个数乘2的操作,即为向左位移1位的操作,而二进制中的每个1,都是进行+1得到的。因此,我们可以遍历n,计算二进制中的1的个数,那么这个个数即为加法次数,最高的1在第几位,就说明经过了几次位移操作,即乘法次数。
通过位运算我们算出每个数的加法次数和乘法次数,返回加法次数和+最大乘法次数即可。
代码:
Python3:
class Solution:
def minOperations(self, nums: List[int]) -> int:
maxxmul = 0
res = 0
# count计算返回n需要的乘法和加法次数
@lru_cache(None)
def count(n):
add = 0
mul = 0
for i in range(31):
# 如果这一位是1,加法++,乘法数为最高位1的位数
if n & 1<<i:
add += 1
mul = i
return add,mul
# 遍历所有的数,累加所有加法次数,加上最大的乘法次数
for num in nums:
add,mul = count(num)
res += add
maxxmul = max(maxxmul,mul)
res += maxxmul
return res
cpp:
class Solution {
public:
int minOperations(vector<int>& nums) {
int maxxmul = 0,res = 0;
// 遍历所有的数,累加所有加法次数,加上最大的乘法次数
for (auto &num:nums){
auto ans = count(num);
res += ans.first;
maxxmul = max(maxxmul,ans.second);
}
res += maxxmul;
return res;
}
// count计算返回n需要的乘法和加法次数
pair<int,int> count(int n){
int add = 0,mul = 0;
for (int i = 0;i < 31; ++i){
// 如果这一位是1,加法++,乘法数为最高位1的位数
if (n & 1<<i ){
add ++;
mul = i;
}
}
return {add,mul};
}
};