Problem Description
Given an array nums consisting of non-negative powers of 2 and an integer target, the goal is to determine the minimum number of operations required so that nums contains a subsequence whose elements sum exactly to target. In one operation, you select any element nums[i] such that nums[i] > 1, remove it, and append two copies of nums[i] / 2 to the end of nums. If it is impossible to obtain such a subsequence, return -1.
Key Insights
- Count the frequency of each power-of-two present in the array.
- Use a greedy approach that tries to “pay” for each bit in target starting from the least significant bit.
- If current resources (frequency at the current bit) are insufficient to cover a needed bit in the target, look for a higher power and split it down until you can cover the deficiency.
- After processing a lower bit, combine leftover elements (every pair of 2^i makes one 2^(i+1)) to use them in upcoming higher bits.
- Checking the total sum first avoids unnecessary computation if the target is unachievable.
Space and Time Complexity
Time Complexity: O(61^2) ≈ O(1) because we only iterate over a fixed number (up to 61) of bit-level positions. Space Complexity: O(61) ≈ O(1) for the frequency array.
Solution
We first count the occurrence of each power-of-two from the nums array into a frequency array indexed by the exponent. Also, we verify that the total sum of the nums is at least target; if not, return -1.
The algorithm iterates from the least significant bit (bit 0) up to an upper bound (e.g. bit 60 when considering target < 2^31 and potential splits). For each bit:
- Carry any extra numbers from lower bits upward (since two copies of 2^i form one 2^(i+1)).
- If the required bit (i.e., if target has a 1 in the i-th position) is missing and there is no available element at that bit, search for the next higher bit that has an available element.
- Once found, perform splitting operations: decrease the count in the higher bit by one and increase the count in the next lower bit by two, incrementing the operation counter on each split, until you reach the desired bit level.
- Finally, "spend" one unit at the current bit to cover the target's requirement.
This greedy splitting ensures the minimal number of operations. The use of a frequency array and the careful combining of lower bits into higher ones allow us to solve the problem efficiently.
Code Solutions
Below are implementations in Python, JavaScript, C++, and Java with line-by-line comments.