题解 | #数值的整数次方#
数值的整数次方
http://www.nowcoder.com/practice/1a834e5e3e1a4b7ba251417554e07c00
描述
这是一篇面对初级coder的题解。
知识点:数学常识 快速幂 递归
难度:一星
题解
题目:
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
保证base和exponent不同时为0。不得使用库函数,同时不需要考虑大数问题,也不用考虑小数点后面0的位数。
即求:浮点数的整数次方
首先补充一些数学上的基础知识:
a0=1 任何数的0次方得1
m-n=(1/m)一个数的负数次方就是一个数的正数次方的倒数
故有下面的预处理函数:
if(exponent==0)
return 1;
if(exponent<0)
{
base=1/base;
exponent=-exponent;
} 方法一:暴力求解
按照乘方的定义 就是连续n个数相乘
class Solution {
public:
double Power(double base, int exponent) {
if(exponent==0)
return 1;
if(exponent<0)
{
base=1/base;
exponent=-exponent;
}
double answer=1 ;//连乘 故初始化为1
for(int i=0; i<exponent;i++)
answer*=base;
return answer;
}
};
运行时间: 8 ms 占用内存:520K
显然,这样执行效率不高 其他语言也类似 需要更好的方法
时间复杂度O(n)
方法二:递归分治的思想
基于的原理如下 若n为偶数 a^n=a^(n/2)*a^(n/2) 若n为奇数 a^n=a^(n/2)*a^(n/2)*a 注意此处的除法为整除 之所以不用除法是为了提高效率
class Solution {
public:
double Power(double base, int exponent) {
if(exponent==0)
return 1;
if(exponent<0)
{
base=1/base;
exponent=-exponent;
}
return Dpower(base,exponent);
}
double Dpower(double b, int n) {
if (n == 1)
return b;
double ret = Dpower(b, n/2);
if (n&1) // 奇数
return ret * ret * b;
else
return ret * ret;
}
};
递归受递归深度限制,同时大家知道,递归虽然简洁,但会产生额外的空间开销。我们可以把递归改写为循环,来避免对栈空间的大量占用
运行时间: 4 ms 占用内存:524K
时间复杂度:O(logn),每次规模减少一半
空间复杂度:O(logn),递归栈,因为要记住logn个变量
方法三:快速幂
本质上采用了数的二进制表示方法 如求7的10次方,但这次,我们把10写成二进制的形式,也就是 1010 即10=0*2^0+1*2^1+0*2^2+1*2^3 考虑a(m+n)=am*an 7^10=7^2^1+7^2^3
class Solution {
public:
double Power(double base, int exponent) {
if(exponent==0)
return 1;
if(exponent<0)
{
base=1/base;
exponent=-exponent;
}
double answer = 1;
while(exponent){
if(exponent&1) //如果n的当前末位为1
answer *= base; //ans乘上当前的a
base *= base; //a自乘
exponent >>= 1; //n往右移一位
}
return answer;
}
};
运行时间: 4 ms 占用内存:512K
时间复杂度:O(logn),因为n的二进制位个数为logn 空间复杂度:O(1)
templateinline T identity_element(plus){
return T(0);
}
templateinline T identity_element(multiplies){
return T(1);
}
templateinline T power_this(T x, Integer n){
return power_this(x, n, multiplies());
}
templateT power_this(T x, Integer n, MonoidOperation op){
if (n == 0)
return identity_element(op);
else{
while ((n & 1) == 0){
n >>= 1;
x = op(x, x);
}
T result = x;
n >>= 1;
while (n != 0){
x = op(x, x);
if ((n & 1) != 0)
result = op(result, x);
n >>= 1;
}
return result;
}
} identity_element(op)为取“证同元素”。所谓“运算op的证同元素”,意思是数值A若与该元素做op运算,会得到A自己。加法的证同元素为0,因为任何元素加上0仍为自己。乘法的证同元素为1,因为任何元素乘以1仍为自己。总结
以2的7次方为例 三种方法总结如下:
可以看做是JZ11的升级版,二进制的数据本身就包含了很多信息
另:数学不好真玩不转计算机
扩展
快速幂的应用广泛
如下面例题中求矩阵的快速幂
阿Q的题解 文章被收录于专栏
阿Q秋招刷过的题

