力扣刷题 -- Pow(x, n)

50. Pow(x, n)

根据题目,需要我们自己定义一个快速求幂的方法 pow(x, n)

方法一:迭代 + 二进制 + 移位。
求解 x n x^n xn 最快速的方法就是循环 n n n 次,将 n n n x x x 乘起来;我们可以利用二进制 和已知的 x x x 来减少循环次数;
假设 n = 11 n=11 n=11,则对应的二进制为 1011 1011 1011,因此结果就会变成
x 11 = x 8 ⋅ x 0 ⋅ x 2 ⋅ x 1 = x 1 ∗ 8 + 0 ∗ 4 + 1 ∗ 2 + 1 ∗ 1 x^{11} = x^8 · x^0 · x^2 · x^1 = x^{1*8 + 0*4 + 1*2 + 1*1} x11=x8x0x2x1=x18+04+12+11
相当于,从 x x x 开始,然后每次循环都进行都对 x 进行赋值操作 x = x 2 = x ⋅ x x = x^2 = x · x x=x2=xx;并且判断 n n n 的二进制最后一位是不是 1(若是 1,则当前的 x x x 与结果相乘,若为 0 则跳过次步),最后进行右移操作。
对于 n < 0,相当于求 1 x n \frac{1}{x^n} xn1,因此将 x x x 取倒数,将 n n n 取反。

流程 myPow(double x, int n)
(1) 定义变量 res = 1;
(2) 若 n != 0, 循环:
① 与操作 n & 1,判断最后一位是否为 1:若结果为 1,则将 res = res * x ,若为 0,则跳过这个步骤;
x 进行赋值操作 x = x*x,并将 n 右移一位 n >>= 1
(3) 返回结果 res

总结:利用二进制,通过不断地将指数 n n n 对半递减(右移),同时通过 x = x 2 x = x^2 x=x2 来累积结果;每当指数的最低位为 1 时,将当前的 x x x 乘入结果中;最终返回 x n x^n xn 的值。

方式二:递归
求解 x n x^{n} xn 时,我们可以看成 x 13 = x 6 + 1 ∗ x 3 ∗ x 1 + 1 ∗ x 0 + 1 ∗ 1 x^{13} = x^{6 + 1} * x^{3} * x^{1+1} * x^{0 + 1} * 1 x13=x6+1x3x1+1x0+11
我们按上面的公式求解 x n x^n xn:我们可以先递归地计算出 y = x ⌊ n / 2 ⌋ y=x^{⌊n/2⌋} y=xn/2
假设递归的结果 y y y,判断 n n n 的奇偶:当 n n n 为奇数时,返回结果就多乘一个 x x x,即 y = y ⋅ x y = y·x y=yx,若是 n n n 为偶数时,就直接返回 y y y 即可。

递归流程 quickMul(x, n)
(1) 终止条件:n == 0,若为 0,则返回 1.0;
(2) 计算 y = quickMul(x, n/2)
(3) 根据 n % 2 == 1 判断 n 的奇偶情况,若为奇数就多乘一个 x x x,若为偶数,则直接返回 y y y

总结:每次递归都会使得指数减少一半,因此递归的层数为 O ( l o g n ) O(logn) O(logn),算法可以在很快的时间内得到结果。

在这里插入图片描述

// 迭代 + 二进制 + 移位
class Solution {
public:
    double myPow(double x, int d) {
        double res = 1;
        long n = d; 

        if (n < 0) {
        	// 这里可能有溢出风险 abs(负数) 
        	// 因此将 n 的数据类型变为 long 
            n = -n;
            x = 1 / x;
        }

        while (n > 0) {
            if (n & 1) 
                res = res * x;
            x = x * x;  
            n = n / 2;   // 右移 1 位  n >>= 1; n = n >> 1
        }
        return res;
    }
};

// 递归
class Solution {
public:
    double myPow(double x, int d) {
        long n = d;
        return n < 0 ? quickMul(1 / x, -n): quickMul(x, n);
    }

    double quickMul(double x, long n) {
        if (n == 0) return 1.0;

        double y = quickMul(x, n/2);
        
        return n % 2 == 1 ? y * y * x: y * y; 
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值