剑指 Offer 16. 数值的整数次方_快速幂法

剑指 Offer 16. 数值的整数次方

题目描述

实现 pow(x, n) ,即计算 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 解释:2-2 = 1/22 = 1/4 = 0.25

提示:

-100.0 < x < 100.0
-231 <= n <= 231-1
-104 <= xn <= 104

题目分析

考虑几种特殊情况:

  1. x和n分别为0, 1时,运行程序会不会有bug
  2. n为负数的时候

Java 代码中 int32 变量 n \in [-2147483648,> 2147483647]n∈[−2147483648,2147483647] ,因此当 n = -2147483648n=−2147483648 时执行 n = -nn=−n 会因越界而赋值出错。解决方法是先将 nn 存入 long 变量 bb ,后面用 bb 操作即可。

最简单的方法是将x循环n次自乘,时间复杂度为O(N)。
需要注意的是n为0的时候, 加一个判断, 结果为1,
你为负数的时候,先将x去倒数,n变成负数,然后再进行循环自乘.
如:

class Solution {
    public double myPow(double x, int n) {
        if(n == 0){
            return 1;
        }
        if(n < 0){
            x = 1/x;
            n = -n;
        }
        double a = x;
        for(int i = 0; i < n - 1; i++){
            x *= a;
        }
        return x;
    }
}

看上去很完美, 结果:
在这里插入图片描述
在这里插入图片描述
emm…

快速幂法

  顾名思义, 快速幂法可以将时间复杂度降低至O(logn)。从“二进制”和“二分法”两个角度理解快速幂法:

二进制角度

一个数二进制和十进制的转换:
已知一个十进制整数 n n n, 其二进制为 m = b m . . . b 3 b 2 b 1 m = b_m...b_3b_2b_1 m=bm...b3b2b1
一个十进制的数使用二进制各位表示:
n = m = 1 b 1 + 2 b 2 + . . . + 2 m − 1 b m n = m = 1b_1 + 2b_2 + ... + 2^{m-1}b_m n=m=1b1+2b2+...+2m1bm
那想求得的 x n x^n xn就等价于:
x n = x 2 0 b 1 + 2 1 b 2 + 2 2 b 3 + . . . + 2 m − 1 b m = x 2 0 b 1 x 2 1 b 2 x 2 2 b 3 . . . x 2 m − 1 b m x^n = x^{2^0b_1+2^1b_2+2^2b_3+...+2^{m-1}b_m} =x^{2^0b_1}x^{2^1b_2}x^{2^2b_3}...x^{2^{m-1}b_m} xn=x20b1+21b2+22b3+...+2m1bm=x20b1x21b2x22b3...x2m1bm
在十进制上求幂=>在二进制上求幂
将式子转换成上面的形式之后, 可以发现, b m b_m bm只能是1或0,当其为0的时候,式子中这一乘项为1,可以忽略不计。这样就省略了很多计算。

这样一来,计算 x n x^n xn就转化成了解决两个问题:

  • 计算 x 2 0 , x 2 1 , x 2 2 , x 2 3 x^{2^0}, x^{2^1}, x^{2^2}, x^{2^3} x20,x21,x22,x23的值:通过循环操作x *= x就可以了;
  • 判断二进制各位的值是否为1,可以通过“判断最后一位是否为1”+“n向右移动一位”两个操作组成
    在这里插入图片描述
    在这里插入图片描述

二分法角度

快速幂法实际上是二分思想的应用:
在这里插入图片描述
在这里插入图片描述
每次判断尾数是不是1, 就是判断 n n n是不是奇数, 如果是奇数, 就将现在的 x x x乘到 r e s res res
每次右移操作不仅是将二进制的最后一个尾数删除,还相当于将原来的十进制数 n n n整除 2 2 2 !

在这里插入图片描述

解答

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;
    }
}

符合判断条件的时候,res才会发生改变,不符合判断条件则不改变,
x x x在每一轮循环都会改变,表示的是系数 x 2 i − 1 x^{2^{i-1}} x2i1

参考:
链接: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/

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值