递归训练三:剑指 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

原题链接:https://leetcode-cn.com/problems/shu-zhi-de-zheng-shu-ci-fang-lcof/

题解

这道题是典型的快速幂算法,但这道题坑比较多,除了要区别 n 是正数还是负数,还要考虑 n 取反溢出的问题。

思路:假设求 7 ^ 11

若将 n 用二进制来表示,则有 11 = 1011
那么 7 ^ 11 可以看成是 7 ^ 11 = 7^1 * 7^2 * 7^0 * 7^8 = 7^1 * 7^2 * 7^8

故我们可以每次判断 n 的二进制数中的最后一位数字是否是 1

是的话结果就必须乘 x,若不是的话,就不处理。
不过不管是不是,x 每一轮都要翻倍。

解决快速幂后,就解决正负数的问题。

一开始没有考虑到 2^31 次方的问题(取相反数后也是 2^31 次方)
故需要用一个 long 类型来接收 n,然后再去取相反数。
先判断 n
(1)正数,不用做操作
(2)0,直接返回 0
(3)负数,转为正数并将 x 倒过来。

递归版本的代码如下

class Solution {
    public double myPow(double x, int n) {
        if (x == 0)         // 若是 0,直接返回
            return 0;
        double res = 1.0;   // 存放结果
        long b = n;         // 用 long 来存储 n
        if (n < 0){         // 考虑负数情况
            x = 1/x;
            b = -b;
        }
        return quitPow(x, b);
    }

    public double quitPow(double x, long n){
        if (n == 0)
            return 1;
        // 位运算,& 是 与 运算,可以用来判断 n 的二进制数的最后一位是否为 1
        if ((n & 1) == 1)
            return x * quitPow(x*x, n >>1 );
        return quitPow(x*x, n >> 1);
    }
}

这里也顺便提供一下非递归版本的代码

class Solution {
    public double myPow(double x, int n) {
        if (x == 0)         // 若是 0,直接返回
            return 0;
        double res = 1.0;   // 结果
        long b = n;         // 用 long 来存储 n
        if (n < 0){         // 考虑负数情况
            x = 1/x;
            b = -b;
        }
        while (b > 0){        // 快速幂
            if ((b & 1) == 1)
                res *= x;
            x *= x;
            b >>= 1;
        }
        return res;
    }
}

相关训练题

递归训练一:Leetcode 104.二叉树的最大深度

递归训练二:Leetcode 62.不同路径

递归训练四:Leetcode 4. 寻找两个正序数组的中位数

发表评论

后才能评论