leetcode
leetcode 1401 ~ 1450
得到目标数组的最少函数调用次数

得到目标数组的最少函数调用次数

难度:

标签:

题目描述

给你一个与 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

代码结果

运行时间: 36 ms, 内存: 23.5 MB


/*
 * 题目思路:
 * 1. 对于每个数字nums[i],我们可以将其转换为二进制表示。二进制中1的个数表示加1操作的次数。
 * 2. 最高位的1所在的位数表示乘以2操作的次数。
 * 3. 我们需要对每个数字计算其加1操作和乘以2操作的总次数,并取最大的乘以2操作次数。
 */
import java.util.stream.IntStream;
public class Solution {
    public int minOperations(int[] nums) {
        int addOperations = IntStream.of(nums)
                                     .map(num -> Integer.bitCount(num))
                                     .sum();
        int maxMultiplyOperations = IntStream.of(nums)
                                              .map(num -> 31 - Integer.numberOfLeadingZeros(num))
                                              .max()
                                              .orElse(0);
        return addOperations + maxMultiplyOperations;
    }
}

解释

方法:

此题解通过反向思维来求解:考虑如何从数组 `nums` 逆向得到全零数组。首先,计算每个数字需要多少次加法操作,即每个数字的二进制表示中 '1' 的个数,这些 '1' 都需要一次加法操作来实现。其次,考虑数组中的最大值,需要乘2的操作次数是最大数的二进制位长度减1(因为从1开始,乘2达到相应长度)。因此,总的操作次数为所有数字需要的加法次数之和加上最大数需要的乘法次数。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
为什么在计算乘2操作的次数时,使用的是最大数的二进制长度减1,而不是直接使用二进制长度?
从1开始乘2到达当前数字需要的次数是该数字二进制长度减1。比如,数字8的二进制为'1000',长度为4,但从1开始,只需要连续乘2三次(1, 2, 4, 8)就可以达到8,故需要减1。
🦆
算法中提到的`op1`是计算所有数字中二进制表示的1的总数,请问这种方法为什么能准确计算出需要的加法操作次数?
每个二进制位的1代表了在那个位置上的加法操作。例如,二进制数'101'代表了在2^0和2^2位置上分别加1,总共两次加法。因此,计算所有数字的二进制中1的总数可以准确得到进行这些加法操作的总次数。
🦆
在代码中,`max(0, max(nums).bit_length() - 1)`使用了`max(0, ...)`,这是为了处理哪些特殊情况?
这是为了处理数组`nums`中含有0的情况。因为0的二进制长度是0,计算`0 - 1`会得到-1,这在逻辑上不成立(因为我们不会做任何乘2操作)。使用`max(0, ...)`是为了确保操作次数不会小于0。
🦆
如果`nums`数组中包含零或负数,这个算法是否仍然有效?为什么?
对于包含零的情况,算法仍有效,因为0的加法操作次数是0,乘法操作次数也被`max(0, ...)`处理。如果包含负数,算法将不适用,因为负数的二进制表示(补码)和算法的逻辑不符,需要额外处理或修改算法逻辑以适应负数。

相关问题