Leetcode刷题笔记——剑指 Offer 16. 数值的整数次方(中等)


题目描述

实现 p o w ( x , n ) pow(x, n) pow(x,n) ,即计算 x x x n n n 次幂函数(即, x n x^n xn)。不得使用库函数,同时不需要考虑大数问题。

解法

x n x^n xn 最简单的方法是通过循环将 n n n x x x 乘起来,依次求 x 1 , x 2 , . . . , x n − 1 , x n x^1, x^2, ..., x^{n-1}, x^n x1,x2,...,xn1,xn ,时间复杂度为 O ( n ) O(n) O(n)
快速幂法 可将时间复杂度降低至 O ( l o g 2 n ) O(log_2 n) O(log2n) ,以下从 “二分法” 和 “二进制” 两个角度解析快速幂法。

快速幂解析(二进制角度):

  • 对于任何十进制正整数 n n n ,设其二进制为 " b m . . . b 3 b 2 b 1 b_m...b_3b_2b_1 bm...b3b2b1 "( b i b_i bi 为二进制某位值, i ∈ [ 1 , m ] i \in [1,m] i[1,m] ),则有:

    • 二进制转十进制: n = 1 b 1 + 2 b 2 + 4 b 3 + . . . + 2 m − 1 b m n = 1b_1 + 2b_2 + 4b_3 + ... + 2^{m-1}b_m n=1b1+2b2+4b3+...+2m1bm (即二进制转十进制公式) ;
    • 幂的二进制展开: x n = x 1 b 1 + 2 b 2 + 4 b 3 + . . . + 2 m − 1 b m = x 1 b 1 x 2 b 2 x 4 b 3 . . . x 2 m − 1 b m x^n = x^{1b_1 + 2b_2 + 4b_3 + ... + 2^{m-1}b_m} = x^{1b_1}x^{2b_2}x^{4b_3}...x^{2^{m-1}b_m} xn=x1b1+2b2+4b3+...+2m1bm=x1b1x2b2x4b3...x2m1bm
  • 根据以上推导,可把计算 x n x^n xn 转化为解决以下两个问题:

    • 计算 x 1 , x 2 , x 4 , . . . , x 2 m − 1 x^1, x^2, x^4, ..., x^{2^{m-1}} x1,x2,x4,...,x2m1 的值: 循环赋值操作 x = x 2 x = x^2 x=x2 即可;
    • 获取二进制各位 b 1 , b 2 , b 3 , . . . , b m b_1, b_2, b_3, ..., b_m b1,b2,b3,...,bm 的值: 循环执行以下操作即可。
      • n & 1 n\And1 n&1 (与操作): 判断 n n n 二进制最右一位是否为 1 1 1
      • n > > 1 n>>1 n>>1 (移位操作) n n n 右移一位(可理解为删除最后一位)。
  • 因此,应用以上操作,可在循环中依次计算 x 2 0 b 1 , x 2 1 b 2 , . . . , x 2 m − 1 b m x^{2^{0}b_1}, x^{2^{1}b_2}, ..., x^{2^{m-1}b_m} x20b1,x21b2,...,x2m1bm 的值,并将所有 x 2 i − 1 b i x^{2^{i-1}b_i} x2i1bi 累计相乘即可。

    • b i = 0 b_i = 0 bi=0 时: x 2 i − 1 b i = 1 x^{2^{i-1}b_i} = 1 x2i1bi=1
    • b i = 1 b_i = 1 bi=1 时: x 2 i − 1 b i = x 2 i − 1 x^{2^{i-1}b_i} = x^{2^{i-1}} x2i1bi=x2i1

在这里插入图片描述
快速幂解析(二分法角度):

  • 二分推导: x n = x n / 2 × x n / 2 = ( x 2 ) n / 2 x^n = x^{n/2} \times x^{n/2} = (x^2)^{n/2} xn=xn/2×xn/2=(x2)n/2 ,令 n / 2 n/2 n/2 为整数,则需要分为奇偶两种情况(设向下取整除法符号为 “ / / // //” ):
    • n n n 为偶数: x n = ( x 2 ) n / / 2 x^n = (x^2)^{n//2} xn=(x2)n//2
    • n n n 为奇数: x n = x ( x 2 ) n / / 2 x^n = x(x^2)^{n//2} xn=x(x2)n//2 ,即会多出一项 x x x
  • 幂结果获取:
    • 根据二分推导,可通过循环 x = x 2 x = x^2 x=x2 操作,每次把幂从 n n n 降至 n / / 2 n//2 n//2 ,直至将幂降为 0 0 0
    • r e s = 1 res=1 res=1 ,则初始状态 x n = x n × r e s x^n = x^n \times res xn=xn×res 。在循环二分时,每当 n n n 为奇数时,将多出的一项
      x x x 乘入 r e s res res ,则最终可化至 x n = x 0 × r e s = r e s x^n = x^0 \times res = res xn=x0×res=res ,返回 r e s res res 即可。

在这里插入图片描述

  • 转化为位运算:
    • 向下整除 n / / 2 n // 2 n//2 等价于 右移一位 n > > 1 n >> 1 n>>1
    • 取余数 n % n \% n% 等价于 判断二进制最右一位值 n & 1 n \& 1 n&1

算法流程:

  1. x = 0 x = 0 x=0 时:直接返回 0 0 0 (避免后续 x = 1 / x x = 1 / x x=1/x 操作报错)。

  2. 初始化 r e s = 1 res = 1 res=1

  3. n < 0 n < 0 n<0 时:把问题转化至 n ≥ 0 n \geq 0 n0 的范围内,即执行 x = 1 / x x = 1/x x=1/x n = − n n = - n n=n

  4. 循环计算:当 n = 0 n = 0 n=0 时跳出;

    1. n & 1 = 1 n \& 1 = 1 n&1=1 时:将当前 x x x 乘入 r e s res res (即 r e s ∗ = x res *= x res=x);
    2. 执行 x = x 2 x = x^2 x=x2 (即 x ∗ = x x *= x x=x );
    3. 执行 n n n 右移一位(即 n > > = 1 n >>= 1 n>>=1)。
  5. 返回 r e s res res

复杂度分析

  • 时间复杂度 O ( l o g 2 n ) O(log_2 n) O(log2n) : 二分的时间复杂度为对数级别。
  • 空间复杂度 O ( 1 ) O(1) O(1) r e s res res, b b b 等变量占用常数大小额外空间。

C++代码实现

class Solution {
public:
    double myPow(double x, int n) {
        if(x == 0) return 0;
        long b = n;
        double res = 1.0;
        if(b < 0) {
            x = 1 / x;
            b = -b;
        }
        while(b > 0) {
            if((b & 1) == 1) res *= x;
            x *= x;
            b >>= 1;
        }
        return res;
    }
};

参考链接

[1] https://leetcode-cn.com/problems/shu-zhi-de-zheng-shu-ci-fang-lcof/solution/mian-shi-ti-16-shu-zhi-de-zheng-shu-ci-fang-kuai-s/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卑微小岳在线debug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值