LeetCode 575 - Distribute Candies
This problem asks us to maximize the number of distinct candy types Alice can eat while respecting a strict limit on how many candies she is allowed to consume. We are given an integer array candyType, where each element represents the type of a candy.
Difficulty: 🟢 Easy
Topics: Array, Hash Table
Solution
Problem Understanding
This problem asks us to maximize the number of distinct candy types Alice can eat while respecting a strict limit on how many candies she is allowed to consume.
We are given an integer array candyType, where each element represents the type of a candy. Multiple candies may share the same type value. The total number of candies is n, and the problem guarantees that n is always even.
The doctor allows Alice to eat only n / 2 candies. Alice wants as much variety as possible, meaning she wants to maximize the number of different candy types among the candies she chooses to eat.
The key observation is that Alice can eat at most n / 2 candies total, so even if there are many unique candy types available, she cannot eat more than n / 2 distinct types because each distinct type requires at least one candy slot.
At the same time, if there are fewer than n / 2 unique candy types in the entire collection, then the answer is simply the number of unique types available.
Therefore, the answer is:
- the number of unique candy types
- capped at
n / 2
Mathematically:
answer = min(number_of_unique_types, n / 2)
The constraints are small to moderate:
2 <= n <= 10^4- Candy values may be negative or positive
nis always even
Since n is only up to 10^4, linear or near-linear solutions are completely acceptable.
Some important edge cases include:
- All candies are the same type, such as
[6,6,6,6] - Every candy is a different type
- The number of unique types is smaller than
n / 2 - The number of unique types is larger than
n / 2 - Negative candy type values
The problem guarantees that the array is non-empty and that n is even, so we do not need special handling for invalid input sizes.
Approaches
Brute Force Approach
A brute-force solution would try every possible subset of size n / 2, then count how many distinct candy types appear in each subset. The maximum distinct count among all subsets would be the answer.
This approach is correct because it explicitly examines every valid selection Alice could make. However, it is computationally infeasible.
If there are n candies, the number of subsets of size n / 2 is:
C(n, n/2)
This grows exponentially and becomes enormous even for moderate values of n.
For example:
C(30,15) = 155,117,520
Trying all combinations would be far too slow.
Optimal Approach
The important insight is that we do not actually need to determine which candies Alice eats. We only need to know the maximum possible number of distinct types.
There are two limiting factors:
- Alice can eat only
n / 2candies total. - Alice cannot eat more distinct types than actually exist.
So if:
- there are
kunique candy types - Alice may eat
n / 2candies
then the maximum distinct types she can eat is:
min(k, n / 2)
A hash set is ideal here because it automatically stores only unique values.
We:
- Insert all candy types into a set
- Count the number of unique types
- Return the minimum of:
- unique count
n / 2
This gives a clean linear-time solution.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(C(n, n/2) * n) | O(n) | Tries every possible candy selection |
| Optimal | O(n) | O(n) | Uses a hash set to count unique candy types |
Algorithm Walkthrough
- Compute how many candies Alice is allowed to eat.
Since the total number of candies is n, Alice may eat:
n / 2
candies. 2. Create a hash set containing all candy types.
A hash set automatically removes duplicates, so after inserting all values, the size of the set equals the number of distinct candy types. 3. Count the number of unique candy types.
This is simply:
len(unique_types)
in Python, or len(map) in Go.
4. Return the smaller value between:
- the number of unique types
- the allowed candy count
Alice cannot eat more than n / 2 candies total, so even if there are more unique types available, she is limited by the number of candies she may consume.
Why it works
The algorithm works because every distinct candy type requires at least one candy to be eaten. Therefore, Alice can never eat more than n / 2 distinct types.
At the same time, Alice also cannot eat more distinct types than actually exist in the collection.
So the true maximum must be the smaller of:
- the total unique candy types
- the allowed number of candies
This guarantees correctness.
Python Solution
from typing import List
class Solution:
def distributeCandies(self, candyType: List[int]) -> int:
unique_types = set(candyType)
max_allowed = len(candyType) // 2
return min(len(unique_types), max_allowed)
The implementation is very compact because Python's built-in set type directly supports the operation we need.
First, we convert the input array into a set. This removes duplicate candy types automatically.
Next, we compute how many candies Alice is allowed to eat, which is half the array length.
Finally, we return the smaller value between:
- the number of unique candy types
- the maximum number of candies Alice may eat
This directly matches the mathematical observation derived earlier.
Go Solution
func distributeCandies(candyType []int) int {
uniqueTypes := make(map[int]bool)
for _, candy := range candyType {
uniqueTypes[candy] = true
}
maxAllowed := len(candyType) / 2
uniqueCount := len(uniqueTypes)
if uniqueCount < maxAllowed {
return uniqueCount
}
return maxAllowed
}
The Go version uses a map to simulate a hash set because Go does not provide a built-in set type.
The map keys represent candy types, and the boolean values are placeholders.
After inserting all candy types into the map, the number of keys equals the number of unique candy types.
Unlike Python, Go does not have a built-in min function for integers, so we use a simple conditional check to return the smaller value.
Worked Examples
Example 1
Input: [1,1,2,2,3,3]
Alice has:
n = 6
She may eat:
6 / 2 = 3
candies.
Step-by-step state
| Step | Candy | Unique Set |
|---|---|---|
| 1 | 1 | {1} |
| 2 | 1 | {1} |
| 3 | 2 | {1,2} |
| 4 | 2 | {1,2} |
| 5 | 3 | {1,2,3} |
| 6 | 3 | {1,2,3} |
Unique types:
3
Maximum allowed candies:
3
Result:
min(3, 3) = 3
Example 2
Input: [1,1,2,3]
Alice has:
n = 4
She may eat:
2
candies.
Step-by-step state
| Step | Candy | Unique Set |
|---|---|---|
| 1 | 1 | {1} |
| 2 | 1 | {1} |
| 3 | 2 | {1,2} |
| 4 | 3 | {1,2,3} |
Unique types:
3
Maximum allowed candies:
2
Result:
min(3, 2) = 2
Example 3
Input: [6,6,6,6]
Alice has:
n = 4
She may eat:
2
candies.
Step-by-step state
| Step | Candy | Unique Set |
|---|---|---|
| 1 | 6 | {6} |
| 2 | 6 | {6} |
| 3 | 6 | {6} |
| 4 | 6 | {6} |
Unique types:
1
Maximum allowed candies:
2
Result:
min(1, 2) = 1
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | We iterate through the array once |
| Space | O(n) | The hash set may store all candy types |
The time complexity is linear because each candy is inserted into the hash set exactly once. Hash set insertion is average-case O(1), so processing all n candies costs O(n).
The space complexity is also O(n) in the worst case, when every candy type is unique and all elements must be stored in the set.
Test Cases
solution = Solution()
assert solution.distributeCandies([1,1,2,2,3,3]) == 3 # Example 1
assert solution.distributeCandies([1,1,2,3]) == 2 # Example 2
assert solution.distributeCandies([6,6,6,6]) == 1 # Example 3
assert solution.distributeCandies([1,2]) == 1 # Minimum valid input
assert solution.distributeCandies([1,2,3,4]) == 2 # All unique types
assert solution.distributeCandies([1,1,1,1,2,2]) == 2 # Fewer unique types than limit
assert solution.distributeCandies([1,2,3,4,5,6]) == 3 # More unique types than limit
assert solution.distributeCandies([-1,-1,-2,-3]) == 2 # Negative candy types
assert solution.distributeCandies([0,0,0,1,2,3]) == 3 # Mix of duplicates and uniques
assert solution.distributeCandies([5,5,5,5,5,5]) == 1 # Single unique type
| Test | Why |
|---|---|
[1,1,2,2,3,3] |
Standard balanced example |
[1,1,2,3] |
Unique count exceeds allowed candies |
[6,6,6,6] |
Only one candy type exists |
[1,2] |
Smallest valid input size |
[1,2,3,4] |
Every candy is unique |
[1,1,1,1,2,2] |
Unique count smaller than eating limit |
[1,2,3,4,5,6] |
Unique count larger than eating limit |
[-1,-1,-2,-3] |
Confirms negative values work correctly |
[0,0,0,1,2,3] |
Combination of duplicates and unique values |
[5,5,5,5,5,5] |
Extreme duplicate-heavy case |
Edge Cases
One important edge case occurs when all candies are the same type. For example:
[6,6,6,6]
Alice may eat two candies, but there is only one distinct type available. A buggy solution might incorrectly return 2 by assuming Alice can always eat n / 2 distinct candies. Our implementation correctly handles this because the set size is 1, and we return the minimum between 1 and 2.
Another important case is when every candy is unique. For example:
[1,2,3,4,5,6]
There are six distinct types, but Alice may eat only three candies. A naive implementation might mistakenly return all six unique types. Our solution correctly caps the answer at n / 2.
A third edge case involves negative candy type values. The constraints allow values from -10^5 to 10^5. Some incorrect implementations may assume candy types are non-negative and attempt array indexing. Our solution uses a hash set, so negative values work naturally without any special handling.
A final edge case is the minimum input size:
[1,2]
Alice may eat only one candy. Even though there are two distinct types, the answer must be 1. The formula min(unique_types, n / 2) handles this correctly and consistently.