【剑指offer】面试题16. 数值的整数次方

7.3号更新

解题思路

本题的细节很多
1、要对无效输入进行判断
2、对指数的不同范围分别进行计算
3、计算Pow函数的优化

平常的Pow函数会这么计算

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

上述代码的时间复杂度O(n),进一步可以采用如下公式简化
image.png
实现代码如下

    double PowerWithUnsignedExponent(double base, long exponent) {
        if (exponent == 0) return 1.0;
        if (exponent == 1) return base;
        double result = PowerWithUnsignedExponent(base, exponent >> 1);//为偶数时
        result *= result;
        if (exponent & 1 == 1)//为奇数时
            result *= base;
        return result;
    }

代码

class Solution {
public:
    bool g_InvalidInput = false;//判断是否为无效输入
    double myPow(double x, int n) {
        if (equal(x, 0.0) && n <= 0) {//无效输入,对于x=0时,n为正数时为0,n为非正数时无意义
            g_InvalidInput = true;
            return 0.0;
        }
        double result;
        long num = n;
        if (n < 0) {//指数小于0
            num = -num;
            return 1.0 / PowerWithUnsignedExponent(x, num);
        }
        //指数大于等于0
        return PowerWithUnsignedExponent(x, num);
    }
    double PowerWithUnsignedExponent(double base, long exponent) {
        if (exponent == 0) return 1.0;
        if (exponent == 1) return base;
        double result = PowerWithUnsignedExponent(base, exponent >> 1);//为偶数时
        result *= result;
        if (exponent & 1 == 1)//为奇数时
            result *= base;
        return result;
    }
    bool equal(double n1, double n2) {//浮点数大小判断
        if (n1 - n2<0.0000001 && n1 - n2>-0.0000001) return true;//|n1-n2|<p
        return false;
    }
};

hints

我发现此处使用unsigned int来保存exponent,过不了当int为负的最小值的case


解题思路

本道题目做了很久才通过,感觉有很多的坑等着自己。
首先刚拿到手,觉得题目很简单,开始时,分了两种情况(指数为正和负)+一些特殊情况(底数为0,指数为0)在做
但运行过程中,仍然有报错,第一个错误时n=-2147483648时的错误,刚开始没有反应过来,后来通过题意,才想明白,自己平时做题也没有去考虑过int型的范围,
在n=-2147483648时,由于我先转换成了abs(n),而正数n最大值为2147483647,因此报错。
第二个遇到的问题是,总是运行超时,一开始我写的pow()函数,是一般的循环算法,但是进行运行测试发现需要2700多ms,所以这种方法不行;
image.png
剑指offer中的公式
参考了剑指offer中的转换为递归的思路,
n为偶数,pow(8)=pow(4)*pow(4),pow(4)=pow(2)*pow(2),pow(2)=pow(1)*pow(1)
n为奇数,pow(9)=pow(4)*pow(4)*base,pow(4)=pow(2)*pow(2),pow(2)=pow(1)*pow(1)
在其编写的代码中,也了解到通过异常捕获,使程序鲁棒性更强,通过位运算,能实运行速度更加地快(B格也高了不少);
总之,学习了。

代码

class Solution {
public:
#define EPSILON 0.000001 //根据精度需要进行调整
	bool g_InvalidInput = false;
	double myPow(double x, int n) {
		//基数为0且指数<0
		if (fabs(x - 0.0) < EPSILON && n <= 0)
		{
			g_InvalidInput = true;
			return 0.0;
		}
		//如果指数为负时,为临界值时,要特殊处理
		if (n == -2147483648) {
			return 1.0 / (x * Pow(x, abs(n + 1)));
		}
		else
		{
			int absN = abs(n);
			//指数<0,返回其倒数
			return n > 0 ? Pow(x, absN) : 1.0 / Pow(x, absN);
		}

	}
	double Pow(double base, int e)
	{
		if (e == 0) return 1;
		if (e == 1) return base;
		//右移1位,相等于/2,位运算速度更快
		double result = Pow(base, e >> 1);
		result *= result;
		//如果指数为奇数,根据公式,最后还要*base
		//此处判断奇数,通过与1相与,速度更快
		if (e & 0x1 == 1) result*= base;
		return result;
	}
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值