Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

1558. Minimum Numbers of Function Calls to Make Target Array - Leetcode Solution

Code Implementation

class Solution:
    def minOperations(self, nums):
        add_ops = 0
        max_doubles = 0
        for num in nums:
            curr_doubles = 0
            n = num
            while n > 0:
                if n % 2 == 1:
                    add_ops += 1
                n //= 2
                if n > 0:
                    curr_doubles += 1
            max_doubles = max(max_doubles, curr_doubles)
        return add_ops + max_doubles
      
class Solution {
public:
    int minOperations(vector<int>& nums) {
        int add_ops = 0, max_doubles = 0;
        for (int num : nums) {
            int curr_doubles = 0;
            int n = num;
            while (n > 0) {
                if (n % 2 == 1)
                    add_ops++;
                n /= 2;
                if (n > 0)
                    curr_doubles++;
            }
            max_doubles = max(max_doubles, curr_doubles);
        }
        return add_ops + max_doubles;
    }
};
      
class Solution {
    public int minOperations(int[] nums) {
        int addOps = 0, maxDoubles = 0;
        for (int num : nums) {
            int currDoubles = 0;
            int n = num;
            while (n > 0) {
                if (n % 2 == 1)
                    addOps++;
                n /= 2;
                if (n > 0)
                    currDoubles++;
            }
            maxDoubles = Math.max(maxDoubles, currDoubles);
        }
        return addOps + maxDoubles;
    }
}
      
var minOperations = function(nums) {
    let addOps = 0, maxDoubles = 0;
    for (let num of nums) {
        let currDoubles = 0;
        let n = num;
        while (n > 0) {
            if (n % 2 === 1)
                addOps++;
            n = Math.floor(n / 2);
            if (n > 0)
                currDoubles++;
        }
        maxDoubles = Math.max(maxDoubles, currDoubles);
    }
    return addOps + maxDoubles;
};
      

Problem Description

Given a target array nums of positive integers, you start with an array of zeros of the same length. You can perform two types of operations any number of times:

  • Increment: Choose any index and increment its value by 1.
  • Double: Double the value of every element in the array.

Your goal is to find the minimum number of function calls (operations) needed to transform the initial zero array into nums. Each operation applies to the whole array (for double) or a single index (for increment). You may not reuse elements; each operation must be a valid step toward the target.

Thought Process

At first glance, it might seem like you need to simulate the process forward: starting from zeros, incrementing elements and doubling the array until you reach the target. However, this quickly becomes inefficient, especially for large numbers.

Instead, let's think in reverse: What if we started from the target array and tried to reduce it to zeros, counting the operations needed? Every time we see an odd number, we know an increment must have occurred. Every time all numbers are even, we know a double operation was used. This reverse approach lets us efficiently count operations without simulating every step.

By analyzing the binary representation of each number, we can see that each '1' bit corresponds to an increment, and the highest bit position corresponds to the number of doubles needed.

Solution Approach

  • Step 1: For each number in nums, count how many times you need to increment (i.e., how many '1's are in its binary representation).
  • Step 2: For each number, count the number of times you need to double (i.e., the position of the highest set bit, or how many times you can divide by 2 until you reach 0).
  • Step 3: The total number of increments is the sum of all increment operations for each number. The total number of doubles is the maximum number of doubles needed for any number (since double applies to the whole array at once).
  • Step 4: Add the total increments and the maximum doubles to get the minimum number of function calls required.

This approach is efficient and avoids simulating every possible operation. It leverages the properties of binary numbers and the allowed operations.

Example Walkthrough

Let's walk through the problem with the sample input nums = [2, 3]:

  1. Binary representations:
    • 2 in binary: 10 (needs 1 double, 1 increment)
    • 3 in binary: 11 (needs 1 double, 2 increments)
  2. Counting increments:
    • 2: 1 increment (for the '1' in the ones place)
    • 3: 2 increments (for both '1's)
    • Total increments: 1 + 2 = 3
  3. Counting doubles:
    • 2: highest bit at position 2 (needs 1 double)
    • 3: highest bit at position 2 (needs 1 double)
    • Maximum doubles: 1
  4. Total operations: 3 increments + 1 double = 4

The sequence of operations could be:
[0, 0] → increment index 0 → [1, 0]
[1, 0] → increment index 1 → [1, 1]
[1, 1] → double all → [2, 2]
[2, 2] → increment index 1 → [2, 3]

Time and Space Complexity

  • Brute-force approach: Simulating every step would be extremely inefficient, potentially O(max(nums) * n) time, as you might need to do many increments and doubles for each element.
  • Optimized approach: For each number, we process at most log₂(max(nums)) steps (for the number of bits). Since we do this for every number, the total time complexity is O(n * log M), where n is the length of nums and M is the maximum value in nums.
  • Space complexity: O(1) extra space (not counting input), since we only use a few variables for counting.

Summary

The key insight in this problem is to reverse the process and analyze the binary representation of each number. Each increment corresponds to a '1' bit, and the highest bit position gives the number of double operations needed. By summing all increments and taking the maximum doubles, we efficiently compute the minimum number of function calls. This approach is both elegant and efficient, leveraging fundamental properties of binary numbers and the allowed operations.