[剑指-Offer] 16. 数值的整数次方(快速幂、递归、代码优化、多方法)

文章目录

    • 1. 题目来源
    • 2. 题目说明
    • 3. 题目解析
      • 方法一:快速幂
      • 方法二:5行高效递归
      • 方法三:迭代法

1. 题目来源

链接:数值的整数次方
来源:LeetCode——《剑指-Offer》专项

2. 题目说明

实现函数 double Power(double base, int exponent),求 baseexponent 次方。不得使用库函数,同时不需要考虑大数问题。

示例1 :

输入: 2.00000, 10
输出: 1024.00000

示例 2:

输入: 2.10000, 3
输出: 9.26100

示例 3:

输入: 2.00000, -2
输出: 0.25000
解释: 2 − 2 2^{-2} 22 = ( 1 2 ) 2 (\frac{1}{2})^2 (21)2 = 1 4 \frac{1}{4} 41 = 0.25

说明:

  • -100.0 < x < 100.0
  • n 是 32 位有符号整数,其数值范围是 [−2^31, 2^31 − 1]

3. 题目解析

方法一:快速幂

快速幂模板问题,不再赘述。注意下 n 为负值时不能直接对其乘以负一,会产生整形溢出的问题,需要将 n 重新赋给一个数据范围更大的类型。double 不在考虑范围内,因为位运算只能用于整形

参见代码如下:

// 执行用时 :8 ms, 在所有 C++ 提交中击败了9.43%的用户
// 内存消耗 :8.3 MB, 在所有 C++ 提交中击败了100.00%的用户

class Solution {
     
public:
    double myPow(double x, int n) {
     
        long q = n;
        if (n < 0) {
     
            x = 1.0 / x;
            q = -q;
        }
        double res = 1;
        while(q) {
     
            if (q & 1)  // 位运算只能用于整形
                res *= x;
            x *= x;
            q >>= 1;
        }
        return res;
    }
};

方法二:5行高效递归

快速幂思想,用递归来折半计算:

  • 每次把 n 缩小一半,这样 n 最终会缩小到 0,任何数的 0 次方都为 1,这时候再往回乘
  • 如果此时 n 是偶数,直接把上次递归得到的值算个平方返回即可
  • 如果是奇数,则还需要乘上个 x 的值
  • 还有一点需要引起注意的是 n 有可能为负数,对于 n 是负数的情况,我可以先用其绝对值计算出一个结果再取其倒数即可,但是测试用例中的 − 2 31 -2^{31} 231,其绝对值超过了整型最大值,会有溢出错误
  • 可以用另一种写法只用一个函数,在每次递归中判断 n 的正负情况针对处理即可

参见代码如下:

// 执行用时 :4 ms, 在所有 C++ 提交中击败了69.36%的用户
// 内存消耗 :8.3 MB, 在所有 C++ 提交中击败了100.00%的用户

class Solution {
     
public:
    double myPow(double x, int n) {
     
        if (n == 0) return 1;
        double half = myPow(x, n / 2);
        if (n % 2 == 0) return half * half;
        if (n > 0) return half * half * x;
        return half * half / x;
    }
};

方法三:迭代法

i 初始化为 n,然后看 i 是否是 2 的倍数,不是的话就让 res 乘以 x。然后 x 乘以自己,i 每次循环缩小一半,直到为 0 停止循环。最后看 n 的正负,如果为负,返回其倒数。

在此就很巧妙避免了,n 为负值产生溢出的情况。

参见代码如下:

// 执行用时 :8 ms, 在所有 C++ 提交中击败了9.43%的用户
// 内存消耗 :8.3 MB, 在所有 C++ 提交中击败了100.00%的用户

class Solution {
     
public:
    double myPow(double x, int n) {
     
        double res = 1.0;
        for (int i = n; i != 0; i /= 2) {
     
            if (i % 2 != 0) res *= x;
            x *= x;
        }
        return n < 0 ? 1 / res : res;
    }
};

你可能感兴趣的:(#,《剑指-Offer》(第二版),《剑指-Offer》,快速幂,递归,代码优化,多方法)