《剑指offer》数值的整数次方

来源:互联网 发布:js钩子函数作用 编辑:程序博客网 时间:2024/05/16 12:22

正在读《剑指offer》,觉得是一本很好的书,希望国内的作者都能写这么好的书,少些《21天精通XXX》。

题目:实现double Power(double base, int exponent), 求base的exponent次方,不得使用库函数,同时不需要考虑大数问题。

自以为题目简单的解法

double Power(double base, int exponent){    double result = 1.0;    for (int i=1; i<=exponent; i++){        result *= base;    }    return result;}

遗憾的是,写得快不一定就写得好,因为面试官会问你要是输入的指数小于1,即是零和负数怎么办?上面的代码完全没有考虑,只包括了指数是正数的情况。

全面的解法,离offer进一步

当指数为负数时,先对指数求绝对值,然后算出结果取倒数。很自然想到,如果底数是0且指数为负,不做特殊处理会导致程序出错。
最后还要指出,任何数的0次方都为1。

bool g_InvalidInput = false;double Power(double base, int exponent){    if (equal(base, 0.0) && (exponent < 0)){        g_InvalidInput = true;        return 0.0;    }    /* 原书有错误,直接赋值了absExponent = (unsigned      int)exponent) ,如果exponent是负数会导致溢出    */    unsigned int absExponent;    if (exponent < 0){        absExponent = (unsigned int)(-exponent);    }else{        /* 大于等于0都可以直接强转 */        absExponent = (unsigned int)(exponent);     }    double result = PowerWithUnsignedExponent(base, absExponent);    if (exponent < 0){        result = 1.0 / result;    }    return result;}double PowerWithUnsignedExponent(base, absExponent){    double result = 1.0;    for (int i=0; i<=exponent; i++){        result *= base;    }    return result;}bool equal(doubel num1, double num2){    if ((num1 - num2 <0.0000001) && (num1 - num2 >-0.0000001)){        return true;    }    else {        return false;    }}

一个细节值得注意,在判断底数是不是0时,我们不能直接写base == 0, 因为在计算机内表示小数(包括float和double都有误差),只能判断它们之差绝对值是不是在一个很小的范围内。这也是我们重写equal的原因。

我们的程序已经考虑得很周详了,已经达到了面试官的要求。但是如果碰到一个在效率上追求完美的人。他则会提醒我们有更高效的办法。

全面高效的解法,确保offer

记得如下公式:

公式不好打字,我直接说明。

当n为偶数时,a**n = (a*n/2) * (a*n/2);
当n为奇数时,a**n = (a*n-1/2) * (a*n-1/2) *a;

所以可以用递归实现O(logn)时间的解法

double PowerWithUnsignedExponent(base, absExponent){    if (exponent == 0){        return 1;    }    if (exponent == 1){        return base;    }    double result = PowerWithUnsignedExponent(base, exponent >> 1);    result *= result;    if (exponent & 0X1 == 1)        reult *= base;    return result;}

最后再提醒一个细节: 我们用右移代替了除以2,用位与运算代替了求余运算%来判断是不是奇数。位运算比乘除法即求余运算高效很多。
既然优化代码,我们就把代码优化到极致。

0 0
原创粉丝点击