1798. Maximum Number of Consecutive Values You Can Make
Problem Description
You have an integer array coins
of length n
, where each element represents the value of a coin you own. You can select any subset of these coins to create a sum equal to some value x
.
Your task is to find the maximum number of consecutive integers that you can create, starting from and including 0
.
For example, if you can create the values 0, 1, 2, 3, 4
, then the answer would be 5
(since you can make 5 consecutive integers starting from 0).
Note that you may have multiple coins with the same value.
The solution works by sorting the coins first, then greedily checking if each coin can extend our current range of consecutive integers. We maintain a variable ans
that represents how many consecutive integers we can currently make (starting from 0).
For each coin value v
in sorted order:
- If
v > ans
, we've found a gap - we cannot make the valueans
, so we stop - Otherwise, if we can already make values
[0, ans-1]
, adding coinv
allows us to make all values in[0, ans-1]
plus[v, v+ans-1]
, effectively extending our range to[0, ans+v-1]
The algorithm returns the total count of consecutive integers that can be formed starting from 0
.
Intuition
The key insight is to think about what range of consecutive integers we can construct at each step. Let's say we can currently make all integers from [0, k-1]
. What happens when we add a new coin with value v
?
If v โค k
, then we can use this coin to extend our range. Why? Because:
- We can already make
0, 1, 2, ..., k-1
- Adding coin
v
means we can also makev, v+1, v+2, ..., v+(k-1)
- Since
v โค k
, these two ranges overlap and merge into one continuous range[0, k+v-1]
However, if v > k
, we have a problem. We can't make the value k
because:
- Without using coin
v
, we can only make up tok-1
- Using coin
v
gives us at minimumv
, which is already greater thank
- This creates a gap at value
k
that we cannot fill
This naturally leads to a greedy approach: sort the coins in ascending order and try to use each coin to extend our current range. Starting with the range [0, 0]
(we can make 0 by selecting no coins), we process each coin:
- If the coin value is small enough (
v โค current_max + 1
), we can extend our range - If the coin value is too large (
v > current_max + 1
), we've found the limit of consecutive integers we can make
The sorting is crucial because using smaller coins first maximizes our ability to create consecutive integers without gaps. Larger coins are more likely to create gaps if used too early.
Solution Approach
The implementation follows a sorting + greedy strategy:
-
Sort the coins array: We sort the
coins
array in ascending order usingsorted(coins)
. This ensures we process smaller valued coins first, which is essential for building consecutive integers without gaps. -
Initialize the answer: We set
ans = 1
, which represents that initially we can make exactly 1 consecutive integer (just0
by selecting no coins). -
Iterate through sorted coins: For each coin value
v
in the sorted array:- Check if we can extend our range: If
v > ans
, it means we cannot construct the valueans
. This is because:- Without using coin
v
, we can make values[0, ans-1]
- Using coin
v
would give us at minimum the valuev
, which is already greater thanans
- Therefore, we have a gap at
ans
that cannot be filled
- Without using coin
- Break if gap found: When
v > ans
, we immediately break and returnans
as our answer - Extend the range: If
v โค ans
, we can use this coin to extend our range. We updateans += v
, meaning we can now make all consecutive integers from0
toans + v - 1
- Check if we can extend our range: If
-
Return the result: After processing all coins (or breaking early),
ans
represents the maximum number of consecutive integers we can make starting from0
.
The time complexity is O(n log n)
due to sorting, where n
is the number of coins. The space complexity is O(1)
if we don't count the space used for sorting.
The algorithm works because at each step, ans
maintains the invariant that we can create all integers in the range [0, ans-1]
. When we add a coin of value v
where v โค ans
, we can create all values in [0, ans-1]
(without the coin) and [v, v+ans-1]
(with the coin), which together form the continuous range [0, ans+v-1]
.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example with coins = [1, 1, 4, 7]
.
Step 1: Sort the coins
- Sorted array:
[1, 1, 4, 7]
- Initialize
ans = 1
(we can make consecutive integers[0]
by selecting no coins)
Step 2: Process first coin (value = 1)
- Check: Is
1 > 1
? No, so we can use this coin - Before this coin: we can make
[0]
(range[0, 0]
) - With this coin: we can also make
[1]
- Combined range:
[0, 1]
- Update:
ans = 1 + 1 = 2
(we can now make 2 consecutive integers: 0 and 1)
Step 3: Process second coin (value = 1)
- Check: Is
1 > 2
? No, so we can use this coin - Before this coin: we can make
[0, 1]
- With this coin: we can make
[1, 2]
(add 1 to each value we could make before) - Combined range:
[0, 2]
- Update:
ans = 2 + 1 = 3
(we can now make 3 consecutive integers: 0, 1, and 2)
Step 4: Process third coin (value = 4)
- Check: Is
4 > 3
? Yes! This means we have a gap - Without this coin: we can make
[0, 2]
- With this coin: minimum value we can make is 4 (using just this coin)
- We cannot make the value 3, so we stop here
Result: Return ans = 3
We can verify this is correct:
- Value 0: select no coins
- Value 1: select the first coin with value 1
- Value 2: select both coins with value 1
- Value 3: cannot be made (gap exists here)
Therefore, the maximum number of consecutive integers starting from 0 is 3.
Solution Implementation
1class Solution:
2 def getMaximumConsecutive(self, coins: List[int]) -> int:
3 # Initialize the maximum consecutive sum we can create starting from 0
4 # We can always create 0, so the next target is 1
5 max_consecutive = 1
6
7 # Sort coins in ascending order to process from smallest to largest
8 sorted_coins = sorted(coins)
9
10 # Iterate through each coin value
11 for coin_value in sorted_coins:
12 # If current coin is greater than our target sum,
13 # we have a gap and cannot form max_consecutive
14 if coin_value > max_consecutive:
15 break
16
17 # If we can form sums [0, max_consecutive - 1] and add coin_value,
18 # we can now form sums [0, max_consecutive + coin_value - 1]
19 max_consecutive += coin_value
20
21 # Return the maximum consecutive integer starting from 0
22 return max_consecutive
23
1class Solution {
2 /**
3 * Finds the maximum number of consecutive integers starting from 0
4 * that can be represented as sums of the given coins.
5 *
6 * The algorithm works by maintaining the invariant that we can form
7 * all integers from 0 to (currentMax - 1). When we add a coin of value v,
8 * if v <= currentMax, we can extend our range to form all integers
9 * from 0 to (currentMax + v - 1).
10 *
11 * @param coins Array of coin values
12 * @return The maximum consecutive integer value starting from 0
13 */
14 public int getMaximumConsecutive(int[] coins) {
15 // Sort coins in ascending order to process from smallest to largest
16 Arrays.sort(coins);
17
18 // Initialize the maximum consecutive value we can form
19 // Starting with 1 means we can initially form integers from 0 to 0
20 int maxConsecutive = 1;
21
22 // Process each coin in sorted order
23 for (int coinValue : coins) {
24 // If current coin value is greater than maxConsecutive,
25 // we have a gap and cannot form the value maxConsecutive
26 if (coinValue > maxConsecutive) {
27 break;
28 }
29
30 // Add current coin value to extend the range of consecutive integers
31 // We can now form all integers from 0 to (maxConsecutive + coinValue - 1)
32 maxConsecutive += coinValue;
33 }
34
35 // Return the count of consecutive integers starting from 0
36 return maxConsecutive;
37 }
38}
39
1class Solution {
2public:
3 int getMaximumConsecutive(vector<int>& coins) {
4 // Sort coins in ascending order to process from smallest to largest
5 sort(coins.begin(), coins.end());
6
7 // Initialize the maximum consecutive integer we can make starting from 0
8 // We can always make 0 (by choosing no coins), so we start checking from 1
9 int maxConsecutive = 1;
10
11 // Iterate through each coin value
12 for (int& coinValue : coins) {
13 // If current coin is greater than maxConsecutive, we have a gap
14 // We cannot form the integer 'maxConsecutive' using available coins
15 if (coinValue > maxConsecutive) {
16 break;
17 }
18
19 // If we can make integers [0, maxConsecutive-1] before this coin,
20 // adding this coin allows us to make [coinValue, maxConsecutive + coinValue - 1]
21 // Combined with existing range, we can now make [0, maxConsecutive + coinValue - 1]
22 maxConsecutive += coinValue;
23 }
24
25 // Return the count of consecutive integers starting from 0
26 return maxConsecutive;
27 }
28};
29
1/**
2 * Finds the maximum number of consecutive integers starting from 0
3 * that can be formed using the given coins
4 * @param coins - Array of coin values
5 * @returns The maximum consecutive integer that can be formed
6 */
7function getMaximumConsecutive(coins: number[]): number {
8 // Sort coins in ascending order to process from smallest to largest
9 coins.sort((a: number, b: number) => a - b);
10
11 // Initialize the current maximum consecutive value we can form
12 // Starting with 1 means we can form all integers from 0 to 0 (just 0)
13 let maxConsecutive: number = 1;
14
15 // Iterate through each coin in sorted order
16 for (const coinValue of coins) {
17 // If current coin is greater than maxConsecutive,
18 // we cannot form maxConsecutive using available coins
19 if (coinValue > maxConsecutive) {
20 break;
21 }
22
23 // Add current coin value to extend the range of consecutive integers
24 // If we can form [0, maxConsecutive-1], adding coinValue
25 // allows us to form [0, maxConsecutive + coinValue - 1]
26 maxConsecutive += coinValue;
27 }
28
29 return maxConsecutive;
30}
31
Time and Space Complexity
Time Complexity: O(n ร log n)
The dominant operation in this code is the sorted()
function, which sorts the coins
array. Python's built-in sorting algorithm (Timsort) has a time complexity of O(n ร log n)
where n
is the length of the array. After sorting, the code iterates through the sorted array once, which takes O(n)
time. Since O(n ร log n) + O(n) = O(n ร log n)
, the overall time complexity is O(n ร log n)
.
Space Complexity: O(log n)
The sorted()
function in Python uses Timsort, which requires O(log n)
space for the recursive call stack in the worst case. The sorted array itself is stored in a new list, but when analyzing space complexity for sorting algorithms, we typically focus on the auxiliary space used by the sorting process itself, which is O(log n)
. The remaining variables (ans
and v
) use constant space O(1)
. Therefore, the overall space complexity is O(log n)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Forgetting to Sort the Array
One of the most common mistakes is processing the coins in their original order instead of sorting them first. The greedy approach only works when we process coins from smallest to largest.
Incorrect approach:
def getMaximumConsecutive(self, coins: List[int]) -> int:
max_consecutive = 1
# Processing coins without sorting - WRONG!
for coin_value in coins:
if coin_value > max_consecutive:
break
max_consecutive += coin_value
return max_consecutive
Why it fails: Consider coins = [1, 4, 10, 3, 1]
. Without sorting, we would process 1 (get range [0,1]), then 4 (cannot use it since 4 > 2), and stop. But if sorted as [1, 1, 3, 4, 10]
, we can make [0,9].
2. Incorrect Initial Value
Starting with max_consecutive = 0
instead of 1
is a subtle but critical error.
Incorrect initialization:
def getMaximumConsecutive(self, coins: List[int]) -> int:
max_consecutive = 0 # WRONG! Should be 1
sorted_coins = sorted(coins)
for coin_value in sorted_coins:
if coin_value > max_consecutive:
break
max_consecutive += coin_value
return max_consecutive
Why it fails: With max_consecutive = 0
, the first coin would always satisfy coin_value > 0
, causing immediate termination. We'd return 0 even when we could form consecutive integers.
3. Misunderstanding the Return Value
Some might think we need to return max_consecutive - 1
(the maximum value we can create) instead of max_consecutive
(the count of consecutive integers).
Incorrect return:
def getMaximumConsecutive(self, coins: List[int]) -> int:
max_consecutive = 1
sorted_coins = sorted(coins)
for coin_value in sorted_coins:
if coin_value > max_consecutive:
break
max_consecutive += coin_value
return max_consecutive - 1 # WRONG! Should return max_consecutive
Why it fails: The problem asks for the count of consecutive integers starting from 0. If we can make [0, 1, 2, 3], that's 4 integers, not 3.
4. Using <= Instead of < in the Break Condition
Using the wrong comparison operator can cause premature termination.
Incorrect comparison:
def getMaximumConsecutive(self, coins: List[int]) -> int:
max_consecutive = 1
sorted_coins = sorted(coins)
for coin_value in sorted_coins:
if coin_value >= max_consecutive: # WRONG! Should be >
break
max_consecutive += coin_value
return max_consecutive
Why it fails: When coin_value == max_consecutive
, we can still use this coin to extend our range. For example, if we can make [0,2] and have a coin of value 3, we can extend to make [0,5].
Solution to Avoid These Pitfalls:
- Always sort the array first
- Initialize with
max_consecutive = 1
(representing that we can make 0) - Use strict inequality
coin_value > max_consecutive
for the break condition - Return
max_consecutive
directly as it represents the count of consecutive integers
How many times is a tree node visited in a depth first search?
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Donโt Miss This!