441. Arranging Coins
Problem Description
You are given n coins and need to build a staircase with them. The staircase follows a specific pattern where:
- Row 1 contains exactly 1 coin
- Row 2 contains exactly 2 coins
- Row 3 contains exactly 3 coins
- And so on...
Each row i must contain exactly i coins. You can only count a row as complete if it has the exact required number of coins. The last row might not have enough coins to be complete, in which case it doesn't count toward your answer.
Your task is to determine how many complete rows you can build with the given n coins.
For example:
- If
n = 5, you can build 2 complete rows (row 1 uses 1 coin, row 2 uses 2 coins, leaving 2 coins which isn't enough to complete row 3 that needs 3 coins) - If
n = 8, you can build 3 complete rows (row 1 uses 1 coin, row 2 uses 2 coins, row 3 uses 3 coins, totaling 6 coins, leaving 2 coins which isn't enough for row 4)
The solution uses a mathematical formula derived from the fact that the sum of the first k natural numbers is k * (k + 1) / 2. By solving the inequality k * (k + 1) / 2 ≤ n for k, we get the formula k = int(sqrt(2) * sqrt(n + 0.125) - 0.5), which directly calculates the number of complete rows.
Intuition
The key insight is recognizing that this is a problem about finding the largest triangular number that doesn't exceed n. When we build the staircase, we're essentially using 1 + 2 + 3 + ... + k coins for k complete rows.
The sum of the first k natural numbers follows the formula k * (k + 1) / 2. So we need to find the largest k where k * (k + 1) / 2 ≤ n.
To solve this, we can rearrange the inequality:
k * (k + 1) / 2 ≤ nk² + k ≤ 2nk² + k - 2n ≤ 0
This is a quadratic inequality. Using the quadratic formula where a = 1, b = 1, and c = -2n, we get:
k = (-1 ± sqrt(1 + 8n)) / 2
Since k must be positive (we can't have negative rows), we take the positive root:
k = (-1 + sqrt(1 + 8n)) / 2
This can be rewritten as:
k = sqrt(2n + 0.25) - 0.5k = sqrt(2) * sqrt(n + 0.125) - 0.5
Since we need the number of complete rows, we take the floor of this value using int(). This mathematical formula directly gives us the answer in constant time without needing to iterate or use binary search.
The beauty of this approach is that it transforms what seems like a counting problem into a mathematical equation that can be solved instantly, regardless of how large n is.
Solution Implementation
1class Solution:
2 def arrangeCoins(self, n: int) -> int:
3 left, right = 1, n
4 first_true_index = 0 # 0 rows if n = 0
5
6 while left <= right:
7 mid = (left + right) // 2
8 # Check if we can form mid complete rows
9 coins_needed = mid * (mid + 1) // 2
10 if coins_needed <= n:
11 first_true_index = mid
12 left = mid + 1 # Try larger k
13 else:
14 right = mid - 1 # k is too large
15
16 return first_true_index
171class Solution {
2 public int arrangeCoins(int n) {
3 long left = 1, right = n;
4 long firstTrueIndex = 0;
5
6 while (left <= right) {
7 long mid = left + (right - left) / 2;
8 long coinsNeeded = mid * (mid + 1) / 2;
9 if (coinsNeeded <= n) {
10 firstTrueIndex = mid;
11 left = mid + 1;
12 } else {
13 right = mid - 1;
14 }
15 }
16
17 return (int) firstTrueIndex;
18 }
19}
201class Solution {
2public:
3 int arrangeCoins(int n) {
4 long long left = 1, right = n;
5 long long firstTrueIndex = 0;
6
7 while (left <= right) {
8 long long mid = left + (right - left) / 2;
9 long long coinsNeeded = mid * (mid + 1) / 2;
10 if (coinsNeeded <= n) {
11 firstTrueIndex = mid;
12 left = mid + 1;
13 } else {
14 right = mid - 1;
15 }
16 }
17
18 return firstTrueIndex;
19 }
20};
211function arrangeCoins(n: number): number {
2 let left: number = 1;
3 let right: number = n;
4 let firstTrueIndex: number = 0;
5
6 while (left <= right) {
7 const mid: number = Math.floor((left + right) / 2);
8 const coinsNeeded: number = Math.floor((mid * (mid + 1)) / 2);
9 if (coinsNeeded <= n) {
10 firstTrueIndex = mid;
11 left = mid + 1;
12 } else {
13 right = mid - 1;
14 }
15 }
16
17 return firstTrueIndex;
18}
19Solution Approach
We use binary search to find the largest number of complete rows k where k * (k + 1) / 2 ≤ n.
Understanding the feasible function:
For a given number of rows k, we need k * (k + 1) / 2 coins to complete all rows. The feasible condition is:
feasible(k) = trueifk * (k + 1) / 2 ≤ n
This creates a boolean pattern:
k: 1 2 3 4 5 ... coins: 1 3 6 10 15 ... feasible: true true true true false ... (when n = 11)
We want to find the last true position, which is equivalent to finding the first k where k * (k + 1) / 2 > n.
Binary Search Template (finding first false, then subtract 1):
left, right = 1, n first_true_index = -1 while left <= right: mid = (left + right) // 2 if mid * (mid + 1) // 2 <= n: # feasible first_true_index = mid left = mid + 1 # Look for larger k else: right = mid - 1 # k is too large return first_true_index
Why this works:
- If
krows can be formed withncoins, we record it and try larger values - If
krows need more coins thann, we try smaller values - The answer is the largest
kwhere the condition is true
Time Complexity: O(log n) - Binary search over the range [1, n]
Space Complexity: O(1) - Only constant extra space used
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with n = 11 coins using binary search.
Step 1: Set up binary search
left = 1,right = 11first_true_index = -1
Step 2: Binary search iterations
Iteration 1: left=1, right=11
mid = (1 + 11) // 2 = 6- Check:
6 * 7 / 2 = 21 > 11→ not feasible right = 5
Iteration 2: left=1, right=5
mid = (1 + 5) // 2 = 3- Check:
3 * 4 / 2 = 6 ≤ 11→ feasible first_true_index = 3,left = 4
Iteration 3: left=4, right=5
mid = (4 + 5) // 2 = 4- Check:
4 * 5 / 2 = 10 ≤ 11→ feasible first_true_index = 4,left = 5
Iteration 4: left=5, right=5
mid = (5 + 5) // 2 = 5- Check:
5 * 6 / 2 = 15 > 11→ not feasible right = 4
Loop ends: left = 5 > right = 4
Answer: first_true_index = 4
Verification: With 4 complete rows, we use:
- Row 1: 1 coin
- Row 2: 2 coins
- Row 3: 3 coins
- Row 4: 4 coins
- Total: 1 + 2 + 3 + 4 = 10 coins
We have 11 coins, so 4 rows use 10, leaving 1 coin. Row 5 would need 5 coins, so we can't complete it.
Time and Space Complexity
Time Complexity: O(log n)
The solution uses binary search over the range [1, n]. In each iteration:
- We calculate the mid value and check if
mid * (mid + 1) / 2 ≤ n - Based on the result, we halve the search space
The number of iterations is proportional to log n, and each iteration performs constant-time arithmetic operations.
Space Complexity: O(1)
The solution only uses a constant amount of extra space for variables (left, right, mid, firstTrueIndex, coinsNeeded). No additional data structures or recursive calls are used.
Common Pitfalls
1. Using Wrong Binary Search Template Variant
A common mistake is using while left < right with left = mid for finding the last true position, which can cause infinite loops.
Incorrect:
while left < right: mid = (left + right + 1) // 2 # Need +1 to avoid infinite loop if mid * (mid + 1) // 2 <= n: left = mid else: right = mid - 1 return left
Correct (template-compliant):
first_true_index = 0 while left <= right: mid = (left + right) // 2 if mid * (mid + 1) // 2 <= n: first_true_index = mid left = mid + 1 else: right = mid - 1 return first_true_index
The template approach avoids the need for +1 adjustments and infinite loop concerns.
2. Integer Overflow in Sum Calculation
When calculating mid * (mid + 1) / 2 for large values of mid, integer overflow can occur.
Incorrect (in Java/C++):
int mid = (left + right) / 2; int sum = mid * (mid + 1) / 2; // Overflow when mid > ~46340
Correct:
long mid = left + (right - left) / 2; long sum = mid * (mid + 1) / 2;
Use long types for intermediate calculations when n can be large.
3. Off-by-One in Search Space
Setting incorrect initial bounds.
Incorrect:
left, right = 0, n # left should start at 1 (at least 1 row possible for n >= 1)
Correct:
left, right = 1, n first_true_index = 0 # Handle n = 0 edge case
4. Forgetting Edge Case n = 0
When n = 0, no rows can be formed. Initialize first_true_index = 0 to handle this case correctly.
Which of the following uses divide and conquer strategy?
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
https assets algo monster cover_photos Binary_Search svg Binary Search Intuition Binary search is an efficient array search algorithm It works by narrowing down the search range by half each time If you have looked up a word in a physical dictionary you've already used binary search in real life Let's
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!