441. Arranging Coins (binary search available)

Title address: https://leetcode.com/problems/arranging-coins/description/

You have a total of n coins that you want to form in a staircase shape, where every k-th row must have exactly k coins.

Given n, find the total number of full staircase rows that can be formed.

n is a non-negative integer and fits within the range of a 32-bit signed integer.

Example 1:

n = 5

The coins can form the following rows:
¤
¤ ¤
¤ ¤

Because the 3rd row is incomplete, we return 2.

Example 2:

n = 8

The coins can form the following rows:
¤
¤ ¤
¤ ¤ ¤
¤ ¤

Because the 4th row is incomplete, we return 3.

// two methods

method one:

class Solution {
    public int arrangeCoins(int n) {
        long lo = 1, hi = n; // The definition of lo and hi as long is purely for the convenience of mid assignment, and the int range is enough
        long mid;
        if (n == 0) return 0;
        while (hi - lo > 1) {
            mid = (lo + hi) >>> 1; // here mid should define long, although there will not be a problem with mid due to addition overflow, but the following expression mid*(1+mid)>>>1 By default int, multiplication overflow may occur, far beyond the range of int, and the extra high-order part of the binary has been truncated, which will lead to incorrect results.
            long sum = mid * (1 + mid) >>> 1; // sum must be long because the int value is 2147483647 and one step will get 1297036691877396480
            if (sum > n) {
                hi = mid;
            } else {
                lo = mid;
            }
        }
        return (int)lo;
    }
}


If you think mid=(lo+hi)>>>1 is difficult to understand, then replace it with mid=lo + ((hi - lo) >>1), because lo is in the int range, hi is in the int range, and hi- lo is also in the int range, and lo+(hi-lo)>>1 is less than hi, so it is also in the int range. About why >>>1 is better, you can read my other blog: https://blog.csdn.net/qq_34115899/article/details/79859973

But >>>1 can only solve the problem of addition overflow , and almost cannot solve the problem of multiplication overflow (unless there is a coincidence like multiplying by 2 and then >>>1, the high-order data is truncated and not saved), the solution is Use a larger data type to handle multiplication overflow.

Method Two:

It is easy to think of directly using mathematical methods

X*(1+X)/2≤n

X+X≤  2n

Here we will use the matching method

4X+ 4X≤ 4*2*n

(2X + 1) - 1 ≤ 8n

2X + 1 ≤

X ≤ 

Write in code:

class Solution {
    public int arrangeCoins(int n) {
        double t = 8.0 * n + 1; // cannot be written as 8*n+1, this expression is the default int, which may exceed the int range and cause the result to be wrong, so replace it with 8.0, and the expression becomes a double type
        return (int)((Math.sqrt(t) - 1) / 2);
    }
}

============================== I am a slow programmer ============= =============

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325947383&siteId=291194637