class Solution:
def arrangeCoins(self, n: int) -> int:
left, right = 0, n
while left <= right:
mid = (left + right) // 2
curr = mid * (mid + 1) // 2
if curr == n:
return mid
if curr < n:
left = mid + 1
else:
right = mid - 1
return right
class Solution {
public:
int arrangeCoins(int n) {
long left = 0, right = n;
while (left <= right) {
long mid = left + (right - left) / 2;
long curr = mid * (mid + 1) / 2;
if (curr == n) return (int)mid;
if (curr < n) left = mid + 1;
else right = mid - 1;
}
return (int)right;
}
};
class Solution {
public int arrangeCoins(int n) {
long left = 0, right = n;
while (left <= right) {
long mid = left + (right - left) / 2;
long curr = mid * (mid + 1) / 2;
if (curr == n) return (int)mid;
if (curr < n) left = mid + 1;
else right = mid - 1;
}
return (int)right;
}
}
var arrangeCoins = function(n) {
let left = 0, right = n;
while (left <= right) {
let mid = Math.floor((left + right) / 2);
let curr = mid * (mid + 1) / 2;
if (curr === n) return mid;
if (curr < n) left = mid + 1;
else right = mid - 1;
}
return right;
};
n
representing the number of coins. Your task is to arrange these coins in a staircase shape, where the first row has 1 coin, the second row has 2 coins, the third row has 3 coins, and so on. Each subsequent row has exactly one more coin than the previous row.
The goal is to find the total number of complete rows of the staircase that can be formed with all n
coins. A complete row is one that is fully filled with coins; if you run out of coins before filling a row, that row is not counted.
n
(0 ≤ n ≤ 231 - 1)n
(1, then 2, then 3, etc.) until you can't subtract anymore. For example, subtract 1 from n
, then 2, then 3, and so on, counting how many times you can do this before n
becomes less than the next number to subtract.
However, for very large values of n
, this approach could be slow because it requires many iterations. To optimize, we can recognize that the total coins needed to form k
complete rows is the sum of the first k
natural numbers: k * (k + 1) / 2
. We need to find the largest k
such that this sum is less than or equal to n
.
This insight allows us to use a more efficient search technique (like binary search) instead of brute-force iteration.
k
rows is k * (k + 1) / 2
. Our goal is to find the largest integer k
such that k * (k + 1) / 2 ≤ n
.
k
increases, we can use binary search to efficiently find the largest valid k
:
left = 0
and right = n
.left ≤ right
:
mid = (left + right) // 2
.curr = mid * (mid + 1) // 2
.curr == n
, return mid
(exact fit).curr < n
, move left
to mid + 1
(try more rows).curr > n
, move right
to mid - 1
(too many coins, try fewer rows).right
will be the largest k
such that the total coins used is not more than n
.O(log n)
time) and works well here because the relationship between k
and the sum is monotonic (always increasing).
n = 8
left = 0
, right = 8
mid = 4
, curr = 4 * 5 / 2 = 10
(too high, right = 3)mid = 1
, curr = 1
(too low, left = 2)mid = 2
, curr = 3
(too low, left = 3)mid = 3
, curr = 6
(still low, left = 4)n
is O(k)
, where k
is the answer (number of rows). In the worst case, this could be up to O(\sqrt{n})
(since the sum of numbers up to k
approaches n
).
O(log n)
.
O(1)
since only a few variables are used.
k
numbers, we can use binary search to efficiently find the answer. This approach is much faster than brute-force and demonstrates the power of combining mathematical insight with algorithmic techniques.