题解 | #数值的整数次方#

数值的整数次方

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)

参考《STL源码剖析》中 Pow函数在STL中的实现——方法是类似的
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秋招刷过的题

全部评论
0乘以任何数都为0,总结里面第三个为0?
点赞 回复 分享
发布于 2023-03-25 15:53 广东

相关推荐

11-09 14:54
已编辑
华南农业大学 产品经理
大拿老师:这个简历,连手机号码和照片都没打码,那为什么关键要素求职职位就不写呢? 从上往下看,都没看出自己到底是产品经理的简历,还是电子硬件的简历? 这是一个大问题,当然,更大的问题是实习经历的描述是不对的 不要只是去写实习流程,陈平,怎么去开会?怎么去讨论? 面试问的是你的产品功能点,是怎么设计的?也就是要写项目的亮点,有什么功能?这个功能有什么难处?怎么去解决的? 实习流程大家都一样,没什么优势,也没有提问点,没有提问,你就不得分 另外,你要明确你投的是什么职位,如果投的是产品职位,你的项目经历写的全都是跟产品无关的,那你的简历就没用 你的面试官必然是一个资深的产品经理,他不会去问那些计算机类的编程项目 所以这种四不像的简历,在校招是大忌
点赞 评论 收藏
分享
Hello_WordN:咱就是说,除了生命其他都是小事,希望面试官平安,希望各位平时也多注意安全
点赞 评论 收藏
分享
2 2 评论
分享
牛客网
牛客企业服务