Problem
Given a sorted integer array nums and an integer n, add/patch elements to the array such that any number in the range [1, n] inclusive can be formed by the sum of some elements in the array.
Return the minimum number of patches required.
Examples
Example 1:
| |
Example 2:
| |
Example 3:
| |
Solution
Method 1 - Greedy
Note that, we should construct all numbers from 1 to n. A dirty take on this problem would be to to go from 1 to n and add all the numbers missing in the array. But certainly this is not the optimal solution. Because we don’t actually need all consecutive numbers to get another by adding them up.
For example, nums = [1, 2, 4].
n = 3, in this case we don’t need 3 to make 3 because we can make 3 by adding 1 and 2. numPatches = 0
n = 5 , we don’t need 5 either, because we can make 5 by adding 1 and 4. numPatches = 0
n = 8, now, we need to add 8 to the list. numPatches = 1. Once we added 8 to the list i.e. nums'=[1, 2, 4, 8] then we don’t need to add any more element until 15 (why?).
Basically, as long as cumulative sum, lets call it maxReach, is greater than the number we need to create , we are good. For instance, if you can make all sums up to 5, and you have a 3 in your set, you can now make all sums up to 8.
But if maxReach falls below the current number (between 1 to n) we need to create , then we have to add the current cumulative sum to itself (why?). If there is a gap, meaning the next number nums[i] is greater than maxReach, we can’t extend the coverage with our existing numbers because you have no way to form maxReach.
This is because we assumed at any particular time maxReach is equal or greater than the current element we need to create. That is we doubling the maxReach when we add a missing element. By always choosing maxReach as the patch when there’s a gap, we are making the greedy choice that gives the smallest next number to cover the widest possible range. Lets look at example below:
- Let’s say
maxReachis4, meaning we can form sums1, 2, 3. - If we patch and add
4, our newmaxReachbecomes8. - We can now create sums
4 (patched number), 5 (1 + 4), 6 (2 + 4), 7 (3 + 4)in addition to our original1, 2, 3.
Any number larger than maxReach would leave a gap. For eg.
- Let’s say
maxReachis4, meaning we can form sums1, 2, 3. - If we patch and add
8, our newmaxReachbecomes12. - We can now create sums
8 (patched number), 9 (1 + 8), 10 (2 + 8), 11 (3 + 8)in addition to our original1, 2, 3. So, it create the gaps:4, 5, 6, 7. Any smaller wouldn’t be possible since all numbers up tomaxReachare already covered.
Algorithm
Here’s the step-by-step approach:
- Initialize
maxReachto 1, since we need to start forming sums from1. - Initialize a variable
patchesto 0, which will store the result - the minimum number of patches required. - Iterate through the array
nums, and for each number tillmaxReach <= n:- While
maxReachis less thannums[i], patch the array withmaxReachand incrementpatchesandmaxReachaccordingly. - Otherwise, update
maxReachto include the current numbernums[i]in the sum to form other numbers.
- While
- If we reach the end of the array and
maxReachis still less thann, we continue adding patches (maxReach + 1) untilmaxReachis at leastn.
Code
| |
| |
Dry Run
Initial Setup
nums = [1, 2, 5, 6, 20]andn = 50.maxReach = 1(maximum sum that can be formed)patches = 0(count how many numbers we need to patch)i = 0(index into thenumsarray)
Iteration 1
- Since
nums[0] = 1, and is in themaxReachboundary - So, we increment the
maxReachto 2.
Iteration 2
- Moving to
nums[1] = 2, we add it to our range since2 <= maxReach. - Update
maxReach = 2 + 2 = 4.
Iteration 3
- Next,
nums[2] = 5. Since5 > maxReach, we cannot include it yet. - We must patch the set first to continue forming all numbers up to
n. - We add
4as the patch, and now we can achieve up tomaxReach + 4 = 8. UpdatemaxReach = 8.
Iteration 4
- Since
nums[2] = 5 <= maxReach, it can now be included. UpdatemaxReach = 8 + 5 = 13.
Iteration 5
nums[3] = 6is already covered by the range[1, 13]since6 < 13. We add it tomaxReach→maxReach = 13 + 6 = 19.
Iteration 6
nums[4] = 20cannot be used immediately since20 > 19. We have to patch the set first.- Add a patch
19to fill the gap. UpdatemaxReach = 19 + 19 = 38.
Iteration 7
- Now we can include
nums[4] = 20because20 <= 38. UpdatemaxReach = 38 + 20 = 58.
End
Since maxReach is now 58, which is greater than n, and we have used 2 patches (4 and 19), the iteration ends here, and the code will return 2 as the minimum number of patches required. These patches have allowed us to form all numbers from 1 to 50 using the given nums array and the patches.