leetcode-Pow(x, n)

136 阅读2分钟

新年好!
突然发现,上一次做算法题已经是一个月前了。虽然每天做一题可能也不会花费很多时间,但是确实很难坚持一段比较长的时间。特意挑选了一个简单一些的题目开始这一年,希望今年每天1题的目标可以有比较高的完成度吧。

题目

实现 pow(xn) ,即计算 x 的 n 次幂函数(即,xn )。

示例 1:
输入: x = 2.00000, n = 10
输出: 1024.00000

示例 2:
输入: x = 2.10000, n = 3
输出: 9.26100

示例 3:
输入: x = 2.00000, n = -2
输出: 0.25000

思路

这是一个快速幂的题目,如果真的做n次乘法,肯定会TLE。
所以,我们优化的核心是怎么减少计算的次数,即减少时间复杂度。
首先,由幂的性质我们知道,如果n可以拆分成数a和b的和,即n=a+b,那么pow(x,n) = pow(x,a) * pow(x,b)。因为我们要尽量减少计算的次数,所以希望pow(x,a) = pow(x,b) = pow(x,n/2),这样我们计算得到pow(x,a)可以被充分利用。
顺着上面的思路,我们可以想到递归的方法:如果n是偶数,pow(x,n) = pow(x,n/2)pow(x,n/2);如果n是奇数,pow(x,n) = pow(x,n/2)pow(x,n/2)x;通过递归的方式计算出结果。
另外一个思路是,把n转换成2进制的形式,n = b0
pow(2,0) + b1
pow(2,1) +...+ bm
pow(2,m),其中,bk归属于(0,1)。这样,我们就从x的0次方(m=0)开始,不断去计算x的pow(2,m)次幂作为temp,如果n转成的2进制数这1位是1,结果就乘以temp。

例如 x = 3, n = 5的情况:
n = 5 = (101)b
353^5 = 313^1 * 343^4
所以,我们可以在计算313^1323^2343^4的过程中,选择二进制对应位数上是1的进行相乘得到结果。

当然,计算temp和判断当前是否要乘以temp可以在一个循环里面进行,通过 n && 1结果是否是1来判断当前n转换成2进制后的最后一位是否1来判断是否要乘以temp,然后通过 n >> 1的方式,将n右移一位来遍历n的二进制每一位。

Java版本代码

class Solution {
    public double myPow(double x, int n) {
        if (x == 0) {
            return 0;
        }
        // 为了保证-n不溢出,先转换成long类型
        long power = n;
        // n是负数时,先转换成正数的情况
        if (power < 0) {
            x = 1 / x;
            power = -power;
        }
        double result = 1.0;
        double temp = x;
        while (power > 0) {
            if ((power & 1) == 1) {
                result *= temp;
            }
            temp *= temp;
            power = power >> 1;
        }
        return result;
    }
}