【JZ-16】数值的整数次方(递归、快速幂)

题目

在这里插入图片描述

方法一-循环乘

即依次求
x 1 x^1 x1, x 2 x^2 x2, …, x n − 1 x^{n-1} xn1, x n x^n xn,时间复杂度为 O ( n ) O(n) O(n)

方法二-快速幂

与简单的循环乘相比时间复杂度可以降低至 O ( l o g 2 n ) O(log_2n) O(log2n)

2.1 二进制角度理解快速幂:

设十进制正整数 n 对应二进制数 b m . . . b 3 b 2 b 1 b_m...b_3b_2b_1 bm...b3b2b1,则有 n = 1 b 1 + 2 b 2 + 2 2 b 3 + . . . + 2 m − 1 b m n=1b_1+2b_2+2^2b_3+...+2^{m-1}b_m n=1b1+2b2+22b3+...+2m1bm
x n = x 1 b 1 ⋅ x 2 b 2 ⋅ x 2 2 b 3 ⋅ . . . ⋅ x 2 m − 1 b m x^n=x^{1b_1}\cdot x^{2b_2}\cdot x^{2^2b_3}\cdot...\cdot x^{2^{m-1}b_m} xn=x1b1x2b2x22b3...x2m1bm
所以原问题转化为解决以下两个问题:

  1. 计算 x 1 , x 2 , x 4 , . . . x 2 m − 1 x^1, x^2,x^4,...x^{2^{m-1}} x1,x2,x4,...x2m1的值
  2. 获取 b 1 , b 2 , b 3 , . . . , b m b_1,b_2,b_3,...,b_m b1,b2,b3,...,bm的值:循环执行【判断最右一位是否为1】和【右移一位】操作。

循环计算 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
2.2 二分法角度理解快速幂:

二分推导: x n = ( x 2 ) n / 2 x^n=(x^2)^{n/2} xn=(x2)n/2,需要区分奇偶两种情况:

  • 当 a 为偶数时, x n = ( x 2 ) ⌊ n / 2 ⌋ x^n=(x^2)^{\left \lfloor n/2\right \rfloor} xn=(x2)n/2
  • 当a 为奇数时, x n = x ⋅ ( x 2 ) ⌊ n / 2 ⌋ x^n=x\cdot (x^2)^{\left \lfloor n/2\right \rfloor} xn=x(x2)n/2
快速幂算法流程:
  1. x = 0 x=0 x=0时,直接返回0
  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 ,   n = − n x=1/x,\ n=-n x=1/x, n=n
  4. 循环计算, n = 0 n=0 n=0 时跳出循环
    当二进制最右一位是1(即 n & 1 = 1 n\And 1=1 n&1=1)时:执行 r e s   ∗  ⁣ =   x res\ *\!=\ x res = x
    执行 x   ∗  ⁣ =   x x\ *\!=\ x x = x
    执行 n 右移一位,即 n   > >  ⁣ =   1 n\ >>\!=\ 1 n >>= 1
  5. 返回 r e s res res
注意:
  1. int32的范围为 [ − 2 31 ,   2 31 − 1 ] \left[-2^{31},\ 2^{31}-1 \right] [231, 2311],所以当 n = − 2 31 n=-2^{31} n=231 时直接执行 n = − n n=-n n=n 会越界,所以应该先将 n 转为 long 型
  2. n < 0 n<0 n<0时,将问题转到 n ≥ 0 n\geq 0 n0范围内这一步里,b 应该用 -b 赋值而非 -n,因为当 n = − 2 31 n=-2^{31} n=231 时 -n 就已经越界了表示不了了
代码:
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;
    }
}
复杂度分析:
  • 时间复杂度: O ( l o g 2 n ) O(log_2n) O(log2n)
  • 空间复杂度: O ( 1 ) O(1) O(1)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值