Distribute Candies to People
EasyPrompt
We distribute some number of candies, to a row of n = num_people people in the following way:
We then give 1 candy to the first person, 2 candies to the second person, and so on until we give n candies to the last person.
Then, we go back to the start of the row, giving n + 1 candies to the first person, n + 2 candies to the second person, and so on until we give 2 * n candies to the last person.
This process repeats (with us giving one more candy each time, and moving to the start of the row after we reach the end) until we run out of candies. The last person will receive all of our remaining candies (not necessarily one more than the previous gift).
Return an array (of length num_people and sum candies) that represents the final distribution of candies.
Example 1:
Input: candies = 7, num_people = 4
Output: [1,2,3,1]
Explanation:
On the first turn, ans[0] += 1, and the array is [1,0,0,0].
On the second turn, ans[1] += 2, and the array is [1,2,0,0].
On the third turn, ans[2] += 3, and the array is [1,2,3,0].
On the fourth turn, ans[3] += 1 (because there is only one candy left), and the final array is [1,2,3,1].Example 2:
Input: candies = 10, num_people = 3
Output: [5,2,3]
Explanation:
On the first turn, ans[0] += 1, and the array is [1,0,0].
On the second turn, ans[1] += 2, and the array is [1,2,0].
On the third turn, ans[2] += 3, and the array is [1,2,3].
On the fourth turn, ans[0] += 4, and the final array is [5,2,3].
Constraints:
- 1 <= candies <= 10^9
- 1 <= num_people <= 1000
Approaches
2 approaches with complexity analysis and trade-offs.
This approach directly simulates the process described in the problem. We maintain the current number of candies to give and the index of the person to receive them. In a loop, we distribute candies turn by turn until we run out.
Algorithm
- Create a result array
ansof sizenum_peopleand initialize all its elements to 0. - Initialize
give = 1to track the number of candies for the current turn. - Initialize
i = 0as the index for the current person. - Start a loop that continues as long as
candies > 0. - Inside the loop, determine the number of candies to give in this turn:
candiesToGive = min(candies, give). - Add
candiesToGivetoans[i]. - Decrease
candiesbycandiesToGive. - Increment
giveby 1 for the next turn. - Update the person index:
i = (i + 1) % num_people. - After the loop terminates, return the
ansarray.
Walkthrough
This method follows the problem description literally. We initialize an integer array ans of size num_people with all elements as 0. We also use a variable give to track the number of candies to be distributed in the current turn, starting from 1, and an index i to point to the current person in the row, starting from 0.
We loop as long as we have candies left. In each iteration, we check if the remaining candies are enough for the current turn. If candies is less than give, the current person receives all the remaining candies. Otherwise, they receive give candies. We update the person's total in the ans array and decrement the total candies. Then, we prepare for the next turn by incrementing give and moving to the next person by updating the index i (wrapping around to the start of the row if necessary).
class Solution { public int[] distributeCandies(int candies, int num_people) { int[] ans = new int[num_people]; int give = 1; int i = 0; while (candies > 0) { int candiesToGive = Math.min(candies, give); ans[i] += candiesToGive; candies -= candiesToGive; give++; i = (i + 1) % num_people; } return ans; }}Complexity
Time
O(sqrt(candies)). Let K be the number of turns. The total candies distributed is the sum of the first K integers, which is `K*(K+1)/2`. This sum is approximately equal to the initial `candies`. Therefore, `K^2` is proportional to `candies`, and `K` (the number of loop iterations) is proportional to `sqrt(candies)`.
Space
O(num_people) to store the result array.
Trade-offs
Pros
Simple to understand and implement.
Works correctly for all valid inputs.
Cons
Can be slow if
candiesis very large (e.g., close to 10^9), as the number of iterations would be around 31,622. This might lead to a 'Time Limit Exceeded' error on some platforms, although it's generally acceptable.
This approach is a significant optimization over simulation. By analyzing the mathematical patterns of the distribution, we can calculate the result in time proportional to the number of people, which is much faster than simulating each candy handout. The key is to determine the total number of gifts given, and then use arithmetic series formulas to find each person's share from the completed rounds.
Algorithm
- Calculate
k, the total number of gifts given, using the formula:k = floor(sqrt(2*candies + 0.25) - 0.5). - Calculate the number of full rounds
p = k / num_people. - Calculate the number of people in the final partial round
extra = k % num_people. - Calculate the candies left over after
kgifts:remaining = candies - k*(k+1)/2. - Initialize a result array
ans. - For each person
ifrom0tonum_people - 1:- Calculate candies from
pfull rounds:full_round_candies = p*(i+1) + num_people*p*(p-1)/2. - Calculate candies from the partial round:
partial_round_candies = (i < extra) ? (p*num_people + i + 1) : 0. - Set
ans[i] = full_round_candies + partial_round_candies.
- Calculate candies from
- Add the remaining candies to the next person in line:
ans[extra] += remaining. - Return
ans.
Walkthrough
First, we determine the total number of successful turns, k, where in each turn t (from 1 to k), we give t candies. The total candies given after k turns is 1 + 2 + ... + k = k*(k+1)/2. We need to find the largest k such that k*(k+1)/2 <= candies.
This inequality k^2 + k - 2*candies <= 0 can be solved using the quadratic formula. The largest integer k is floor(sqrt(2*candies + 0.25) - 0.5). This gives us the total number of gifts handed out.
With k total gifts, we can determine the number of full rounds of distribution. A full round gives candies to all num_people. The number of full rounds is p = k / num_people.
The number of people who receive gifts in the final, incomplete round is extra = k % num_people.
The candies remaining after k gifts are given out is remaining = candies - k*(k+1)/2.
Now, we can calculate the candies for each person i (0-indexed):
- Candies from full rounds: In
pfull rounds, personireceives(i+1), (i+1)+n, ..., (i+1)+(p-1)n. This is an arithmetic series with sump*(i+1) + n*p*(p-1)/2. - Candies from the final partial round: If person
iis one of theextrapeople in the final round (i < extra), they receive an additional gift ofp*n + (i+1)candies. - Leftover candies: The
remainingcandies are all given to the person who would have received the(k+1)-th gift, which is person at indexextra.
We sum these parts for each person. Note that long should be used for intermediate calculations to avoid integer overflow.
class Solution { public int[] distributeCandies(int candies, int num_people) { // Find the largest k such that 1 + 2 + ... + k <= candies // k*(k+1)/2 <= candies => k^2 + k - 2*candies <= 0 // Solving for k gives k <= (sqrt(8*candies + 1) - 1) / 2 // which is equivalent to floor(sqrt(2*candies + 0.25) - 0.5) long k = (long)(Math.sqrt(2.0 * candies + 0.25) - 0.5); long remaining_candies = (long)candies - (k * (k + 1) / 2); // Number of full rounds long p = k / num_people; // Number of people in the last partial round int extra_people = (int)(k % num_people); int[] ans = new int[num_people]; for (int i = 0; i < num_people; i++) { // Candies from p full rounds for person i // They get (i+1), (i+1)+n, ..., (i+1)+(p-1)n // Sum = p*(i+1) + n*(0+1+...+(p-1)) = p*(i+1) + n*p*(p-1)/2 long total = p * (i + 1) + (long)num_people * p * (p - 1) / 2; // Candies from the last partial round (if person i is in it) if (i < extra_people) { total += p * num_people + (i + 1); } ans[i] = (int)total; } // The very last person gets all remaining candies ans[extra_people] += (int)remaining_candies; return ans; }}Complexity
Time
O(num_people). The calculation of `k` (total turns) is O(1). The main work is a single loop that iterates `num_people` times to calculate the final distribution for each person. All calculations inside the loop are O(1). Since `num_people` is much smaller than `sqrt(candies)` for large `candies`, this is the most efficient approach.
Space
O(num_people) to store the result array.
Trade-offs
Pros
Extremely efficient, with a time complexity independent of the number of candies.
Avoids potential 'Time Limit Exceeded' errors for very large inputs.
Cons
The logic is more complex and relies on mathematical formulas for arithmetic series.
Requires careful handling of large numbers (using
longin Java) to prevent integer overflow during intermediate calculations.
Solutions
Solution
class Solution {public int[] distributeCandies(int candies, int num_people) { int[] ans = new int[num_people]; for (int i = 0; candies > 0; ++i) { ans[i % num_people] += Math.min(candies, i + 1); candies -= Math.min(candies, i + 1); } return ans; }}class Solution: def distributeCandies(self, candies: int, num_people: int) -> List[int]: ans = [0] * num_people i = 0 while candies: ans[i % num_people] += min(candies, i + 1) candies -= min(candies, i + 1) i += 1 return ansclass Solution {public: vector<int> distributeCandies(int candies, int num_people) { vector<int> ans(num_people); for (int i = 0; candies > 0; ++i) { ans[i % num_people] += min(candies, i + 1); candies -= min(candies, i + 1); } return ans; }};Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.