A clear explanation of Distribute Candies using a set to count candy types and a simple limit argument.
Problem Restatement
We are given an integer array candyType.
Each integer represents one candy type.
Alice has n candies total, where n = len(candyType). She is allowed to eat exactly n / 2 candies.
Return the maximum number of different candy types Alice can eat.
The array length is even. The constraints include n == candyType.length, 1 <= n <= 10^4, n is even, and -10^5 <= candyType[i] <= 10^5. The examples include [1,1,2,2,3,3], output 3, and [1,1,2,3], output 2.
Input and Output
| Item | Meaning |
|---|---|
| Input | An integer array candyType |
| Output | Maximum number of different candy types Alice can eat |
| Alice eats | Exactly len(candyType) / 2 candies |
| Goal | Maximize the number of distinct types eaten |
Example function shape:
def distributeCandies(candyType: list[int]) -> int:
...Examples
Example 1:
candyType = [1, 1, 2, 2, 3, 3]There are 6 candies, so Alice can eat:
6 / 2 = 3candies.
The distinct candy types are:
{1, 2, 3}There are exactly 3 types, and Alice can eat 3 candies, so she can eat one candy of each type.
The answer is:
3Example 2:
candyType = [1, 1, 2, 3]There are 4 candies, so Alice can eat:
4 / 2 = 2candies.
There are 3 distinct types:
{1, 2, 3}But Alice can only eat 2 candies, so she can eat at most 2 different types.
The answer is:
2Example 3:
candyType = [6, 6, 6, 6]Alice can eat 2 candies, but there is only one candy type.
The answer is:
1First Thought: Count Types
To maximize the number of different types, Alice should avoid eating duplicate types whenever possible.
So the useful information is not the exact count of every type. We only need to know how many different types exist.
For example:
[1, 1, 1, 1, 2, 3]has three distinct types:
1, 2, 3Alice can eat three candies, so she can eat one candy of each type.
Key Insight
There are two upper limits on the answer.
First, Alice cannot eat more different types than the number of candies she eats:
len(candyType) // 2Second, Alice cannot eat more different types than the number of distinct types available:
len(set(candyType))The best possible answer is the smaller of these two values.
So:
answer = min(len(candyType) // 2, len(set(candyType)))Algorithm
Compute the number of candies Alice can eat:
limit = len(candyType) // 2Count the number of distinct candy types:
types = len(set(candyType))Return:
min(limit, types)
Correctness
Alice eats exactly len(candyType) // 2 candies. Since each eaten candy can contribute at most one new type, the answer can never be greater than len(candyType) // 2.
Also, Alice cannot eat a type that does not exist. Therefore, the answer can never be greater than the number of distinct values in candyType.
So the answer is at most:
min(len(candyType) // 2, len(set(candyType)))This upper bound is always achievable.
If there are at least len(candyType) // 2 distinct types, Alice can choose one candy from that many different types.
If there are fewer than len(candyType) // 2 distinct types, Alice can choose one candy from every type, then fill the remaining candies with duplicates. The number of different types eaten is then exactly the number of distinct types.
Therefore, the algorithm returns the maximum possible number of different candy types Alice can eat.
Complexity
Let n = len(candyType).
| Metric | Value | Why |
|---|---|---|
| Time | O(n) | Building the set scans the array once |
| Space | O(n) | The set may store all candy types |
Implementation
class Solution:
def distributeCandies(self, candyType: list[int]) -> int:
return min(len(candyType) // 2, len(set(candyType)))Code Explanation
The expression:
len(candyType) // 2is the number of candies Alice is allowed to eat.
The expression:
len(set(candyType))counts how many distinct candy types exist.
Taking the minimum gives the maximum variety Alice can achieve without exceeding the eating limit.
Counting With Early Stop
We can stop counting once we already have enough distinct types.
class Solution:
def distributeCandies(self, candyType: list[int]) -> int:
limit = len(candyType) // 2
seen = set()
for candy in candyType:
seen.add(candy)
if len(seen) == limit:
return limit
return len(seen)This version has the same worst-case complexity, but it can finish earlier when many distinct types appear near the beginning.
Testing
def run_tests():
s = Solution()
assert s.distributeCandies([1, 1, 2, 2, 3, 3]) == 3
assert s.distributeCandies([1, 1, 2, 3]) == 2
assert s.distributeCandies([6, 6, 6, 6]) == 1
assert s.distributeCandies([1, 2]) == 1
assert s.distributeCandies([-1, -1, 0, 1]) == 2
assert s.distributeCandies([1, 2, 3, 4, 5, 6]) == 3
print("all tests passed")
run_tests()| Test | Why |
|---|---|
[1, 1, 2, 2, 3, 3] | Main sample with exactly enough types |
[1, 1, 2, 3] | More types than Alice can eat |
[6, 6, 6, 6] | Only one type exists |
[1, 2] | Small even-length input |
[-1, -1, 0, 1] | Negative candy type values |
[1, 2, 3, 4, 5, 6] | All candies have different types |