• Medium | LeetCode 50 | 剑指 Offer 16. 数值的整数次方 | 递归 | 快速幂


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

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

    示例 1:

    输入: 2.00000, 10
    输出: 1024.00000
    

    示例 2:

    输入: 2.10000, 3
    输出: 9.26100
    

    示例 3:

    输入: 2.00000, -2
    输出: 0.25000
    解释: 2-2 = 1/22 = 1/4 = 0.25
    

    说明:

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

    方法一: 递归

    1. 递归关系:当exponent为偶数时, Power(base, exponent) = Power(base*base, exponent/2)
      当exponent为奇数时, Power(base, exponent) = base * Power(base*base, exponent/2)

    2. 递归出口: 当exponent = 1时, 返回base;

    /**
     * 方法一 : 采用递归的方式求幂
     */
    public double myPowerUnsign1(double x, long n) {
        if (n == 0) {
            return 1;
        }
        if (n == 1) {
            return x;
        }
        double res = myPowerUnsign(x, n >> 1);
        if ((n & 0x1) == 1) {
            return x * res * res;
        }
        return res * res;
    }
    

    方法二: 快速幂

    方法一是自上而下的递归的方法, 也可以采用自下而上的循环迭代的方法。

    1. 先考虑exponent为偶数的情况, 比如求 2 ^ 16, 此时base = 2, exponent = 16, 每次迭代 base = base * base, exponent /= 2, 迭代过程如下:

      base exponent
      2 16
      4 8
      16 4
      256 2
      256 * 156 1

    可以看到 base和exponent实际上是一个同步此消彼长的过程。

    1. 如果exponent是奇数, 比如说求 3^15 次方, 迭代过程如下

      base exponent 写为
      3 15 3 * 3 ^ 14 = 3 * 9 ^ 7
      9 7 9 * 81 ^ 3

      每次遇到奇数的迭代过程, 都会留下一个base值没有参与到下一次的迭代, 所以每逢遇到奇数, 都要把当前的这个base值计算进结果里。

    2. 要写一个完整的程序, 还需要考虑一下几个小细节。

      3.1 幂值是可以为负数的

      3.2 0的负数幂是错误的, 应该让用户知道, 可以选择抛异常, 设置返回状态码等方式告诉用户

    public double myPow(double x, int n) {
        // 错误值
        if (x == 0 && n < 0) {
            return 0.0;
        }
        double res = myPowerUnsign(x, Math.abs((long)n));
        if (n < 0) {
            return 1/res;
        }
        return res;
    }
    
    /**
     * 方法二 : 采用迭代的方式求幂
     */
    public double myPowerUnsign2(double x, long n) {
        if (n == 0) {
            return 1;
        }
        if (n == 1) {
            return x;
        }
        double res = 1.0;
        while (n > 0) {
            if ((n & 0x1) == 1) {
                // 当奇数时, 会将底数乘进结果集里
                // 最终一定会回到n = 1的情况, 这种情况也是将最终迭代的结果计算进res的情况, 
                // 其他的情况只不过是x和n此消彼长的过程, 并不将迭代的结果计算进res里
                res *= x;
            }
            // x 和 n 此消彼长
            x *= x;
            n >>= 1;
        }
        return res;
    }
    
  • 相关阅读:
    三列布局_左右绝对定位_中间适应
    三列布局_左右固定_中间自适应
    两列布局_左右二侧_绝对定位
    二列布局_左右固定_自己撑开父级块
    两列布局_右侧固定_左侧自适应
    两列布局_左侧固定_右侧自适应
    单列布局_宽度自适应_内容居中
    单列布局_上中下等宽
    聊一聊Unity协程背后的实现原理
    发火箭和做游戏有什么共通点?
  • 原文地址:https://www.cnblogs.com/chenrj97/p/14280836.html
Copyright © 2020-2023  润新知