【精】leetcode

来源:互联网 发布:大数据成熟度模型 编辑:程序博客网 时间:2024/05/20 00:12

题目

You have a total of n coins that you want to form in a staircase shape, where everyk-th row must have exactlyk 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 = 5The coins can form the following rows:¤¤ ¤¤ ¤Because the 3rd row is incomplete, we return 2.

Example 2:

n = 8The coins can form the following rows:¤¤ ¤¤ ¤ ¤¤ ¤Because the 4th row is incomplete, we return 3.

题意

你一共有n个硬币,你需要将其摆成阶梯的形状,在这个阶梯中 第 k行 一定要有 k个硬币。

给定一个n,找出可以形成的完整阶梯的总数。

n是一个非负整数,在带符号的32位整数范围内。

注意:

(1)关于数值类型的范围

  • 笔试题】大部分笔试题主要用到的数据类型为整数类型,这时候double这些具有高位数的便可以 当作辅助工具。
  • 正常情况】这到题目看似比较简单,我们能够轻易解出 n 为正常值得情况。
  • 数值类型的范围】32位有符号整数 范围为:  -2^31 ~ 2^31-1( 2 147 483 647
  • 非正常情况 + 难点】你需要考虑当 n 非常接近于32位正整数的最大值得情况,此时你对于n的运算(如:与整数的除法,平方)可能导致数值溢出。举个简单的例子:假如n =1 804 289 383(< 2 147 483 647), 这意味着 n *2 就会超过32位整数的最大值,进而导致错误(在java中输出结果为:-686388530)。   ---->  所以,在我们的程序中一定得小心对于整数的运算
  • 需要注意的运算】 加法 , 乘法,平方等,这些计算都会使数值增加。

(2)关于二分查找

下面简单说说二分查找的一些特征:

  • 【作用】二分查找基本上每次都会将范围降低为原来的一半。
  • 【适用的场景】二分查找 需要建立在 待查找数值具有次序的基础上。


分析及解答

借鉴网友的算法,具体的连接可以见:(网友的算法及解释)

接下来,我会从两个角度来说明这个算法需要注意的地方:

  1. 控制数值的范围
  2. 二分查找

(1)控制数值的范围

  • 【技巧:整数范围有限,所以转化为 double类型,范围变广】mid * mid如果计算结果被认为是整数的情况的话,那么在运行的时候一定会溢出,所以作者巧妙的在前面加了0.5,也就是告诉了编译器:“经过计算后,我变成了double类型的数据了”。  ---->  而在java中 double 类型的数值,是64位的,远远大于32位的int 。
    0.5 * mid * mid

(2)二分查找

  • 为何用二分查找?】在该题目中,需要计算一定范围的数的和,然后与 n 进行比较。仔细观察可以发现,起点是固定的,主要的问题就在于确定终点,再加上具有次序性,于是便可以使用二分查找。
  • 核心公式】假如说最大行为 m ,那么 m 满足 :m * (m +1)/ 2  <= n.

代码:

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;    }}

我的解法(低效算法)

* 为何低效?

public class Solution {    public int arrangeCoins(int n) {        if(n == 0) return 0;        if(n == 1) return 1;        int i =0;        i = (int)(Math.sqrt(n*2.0)); // java封装的开方本身就会消耗大量的时间。        for(; 0.5*i*(i+1) > n ;i--){        }        return i;    }}