c 等差数列应用arranging coins 多种实现方法

来源:互联网 发布:厨师机 知乎 编辑:程序博客网 时间:2024/06/06 02:17
  • 题目描述
    这里写图片描述
    这里写图片描述

  • 分析(实现方法1)
    由题知每行(第1行、第2行…)coin的变化是1,2,3,4,5…..,即等差数列。若第k行刚好填满,则所有的coins数为Sk= k(k+1)/2。

    假设令2*Sk=m*m,则k(k+1)=m*m,可得m*m>k*k。也即k势必会比2*Sk开方的值小,但不会小太多。对于输入n,那么我们可以从m(m=sqrt(2*n))开始验算,看其附近有没有满足k(k+1)=2*n的存在,有,则说明coin的最后一行都是排满的。没有的话,那么第一个小于2*n的k值即为最大的行数值。

  • 代码实现(对应实现方法1)

int arrangeCoins(int n) {    double pro;    int k;    if(n==0||n==1)        return n;    k=(int)(sqrt(2)*sqrt(n));  //若写成sqrt2*n),则2*n存在数值溢出的风险,如n=1804289383时,2*n就溢出了。    pro=k*(k+1);    while(pro>2*n){        k=k-1;        pro=k*(k+1);    }    return k;}

该方法实现时需要注意一点便是注释中话,以及该语句中int强制转化的值对象。

  • 分析(实现方法2,只是头脑风暴下,该方法效率太低)
    在上述代码中用到了sqrt,那我们可不可以把它去掉呢?可以(注意:k(k+1)=2*n可以变成(k+1)=2*n/k,开根就没了)。法1中我们是从某个值减着去验证,下面贴出的方法是从头开始加着去验证。

  • 代码实现(对应实现方法2)

int arrangeCoins(int n) {    int k;    if(n==0||n==1)        return n;    k=2;  // k不能从1取,不然下述代码的n/k*2就存在溢出的风险。    while((k+1)<=n/k*2){  // n/k*2的顺序不能换成n*2/k,不然n*2存在溢出的风险        k++;    }    if(k==n/(k+1)*2)   // 之所以还要加这个判断是因为n/k的值已把小数点去掉了(int型),值不准确(变小)了        return k;    else        return k-1;}

上述代码还需注意一个细节,if(k==n/(k+1)*2)不能写成if(k+1==n/k*2),不然程序会运行错误。如下图所示,
这里写图片描述
为什么呢?因为n/k的值是不准确的,小数点后的值被舍弃了。同样n/(k+1)也是不准确的,只是本题给的所有测试用例中,没有受其影响的例子。

所以,综述所述,上述代码要想使用if(k+1==n/k*2)最的话,需要写成if(k+1==(int)((double)(n)/k*2)), 即先保留小数点进行计算,再转成整型进行比较。

  • 分析(实现方法3)
    该题还有其他方法,比如说二分查找。low=1,high=n,mid=(low+high)/2开始逼近搜索。

  • 代码(对应实现方法3)

int arrangeCoins(int n) {    int low=1,high=n,mid;    if(n==0)        return 0;    while(low<=high){        mid=low+(high-low)/2;  // 不写成(low+high)/2是因为有溢出的风险        if(mid==(double)(n)/(mid+1)*2)            break;        else if(mid<(double)(n)/(mid+1)*2)            low=mid+1;        else            high=mid-1;    }    if(mid<=(double)(n)/(mid+1)*2)        return mid;    else        return mid-1;}
  • 时耗分析
    法3的效率最高,法1次之,法2最低。
    这里写图片描述
    上图是法3的时耗截图。
0 0
原创粉丝点击