ArrangingCoins [source code]

public class ArrangingCoins {
static
/******************************************************************************/
public class Solution {
    public int arrangeCoins(int n) {
        long sum = 0;
        int i = 1;
        while (sum <= n) {
            sum += i++;
        }
        return i - 2;
    }
}
/******************************************************************************/

    public static void main(String[] args) {
        ArrangingCoins.Solution tester = new ArrangingCoins.Solution();
        int[] inputs = {4, 5, 8, 1804289383, 2147483647, 846930886};
        for (int i : inputs) System.out.println(i + " -> " + tester.arrangeCoins(i));
        // System.out.println(tester.arrangeCoins(846930886));
    }
}

也是好久没有见过这么恶心的题目了; 刚开始这个题目是很简单的思路, 就是直接用求和公式来做, 最后的结果肯定是在平方根的周围浮动:

public class Solution {  
    public int arrangeCoins(int n) {  
        int root = (int) Math.sqrt(2 * n);  
        if ((long) (root * (root + 1)) <= 2 * n) return root;  
        else return root - 1;  
    }  
}

但是立刻这个 code 就被 break 了, 就是用 overflow:

java> long n1 = 60070 * 60071  
long n1 = -686502326  
java> Math.sqrt(2 * 1804289383)  
java.lang.Double res6 = NaN

乘法和平方根都用不起来了;

最后只能用穷举, 也就是求和的思路来做; 就是这样, 还是有一个 overflow 的case; 原因是 sum 这个累加和, 要用 long 来避免overflow;

最后的速度是54ms (42%), 这个题目反正是没什么好说的了;


这个是 submission 上面的一个最优解:

public class Solution {  
    public int arrangeCoins(int n) {          
        return (int) (Math.sqrt(8.0*n+1)-1)/2;  
    }  
}

这个其实速度也没比我的快多少: 52(49); 不过代码很简洁; 这个方法我主要是没有想到, 实际上也没有复杂多少, 就是把那个二次方程的解直接解出来了;


这个是 discussion 上面看到的另外一个方法, 这个方法比我的方法更加先进一点:

public class Solution {  
    public int arrangeCoins(int n) {  
        int start = 0;  
        int end = n;  
        int mid = 0;  
        while (start <= end){  
            mid = (start + end) >>> 1;  
            if ((0.5 * mid * mid + 0.5 * mid ) <= n){  
                start = mid + 1;  
            } else {  
                end = mid - 1;  
            }  
        }  
        return start - 1;  
    }  
}

讲实话 Binary Search 实际上我也是想到了的, 不过没有想去做, 这题最好还是能够想到这个方法; 从头开始搜是在是太蠢了;
同样的, 一个问题前面已经强调过好几次了, 就是注意 Binary Search 的标准写法, 另外, 这里他的 if 的 header 里面用的是左边乘0.5而不是右边乘2, 这个一定程度上也是为了避免 overflow;

事实上, 这个是作者的说法:
Note that 0.5 mid mid + 0.5 * mid does not have overflow issue as the intermediate result is implicitly autoboxed to double data type.

也就是说, 这里他还故意用了 double 来做一个防止 overflow 的处理;


Problem 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.

Difficulty:Easy
Total Accepted:28.1K
Total Submissions:77.6K
Contributor: LeetCode
Companies
godaddy
Related Topics
binary search math

results matching ""

    No results matching ""