50.Pow(x,n)

1.题目介绍

2.题解

本题的方法被称为「快速幂算法」,有递归和迭代两个版本。这篇题解会从递归版本的开始讲起,再逐步引出迭代的版本。
当指数 n为负数时,我们可以计算 x^-n再取倒数得到结果,因此我们只需要考虑 n 为自然数的情况。

2.1 模拟(不推荐,时间复杂度过高)

思路

分为n>=0, n<0情况分别计算Pow(x,n)

代码

class Solution {
public:
    double myPow(double x, int n) {
        double ans = 1;
        int num = n >=0 ? n:-n;
        for(int i = 0; i < num; i++){
            ans *= x;
        }
        if(n < 0) ans = 1.0 / ans;
        return ans;
    }
};

2.2 快速幂 + 递归

思路


由于每次递归都会使得指数减少一半,因此递归的层数为 O(log⁡n),算法可以在很快的时间内得到结果。

代码

class Solution {
public:
    double quickMul(double x, long long N) {
        if(N == 0) return 1.0;
        double y = quickMul(x, N / 2.0);
        return N % 2 == 0? y*y : y*y*x;
    }
    
    double myPow(double x, int n) {
        long long N = n; // 这里为何要强转为long long? 因为后面-n进行取反时,-2147483648(INT_MIN,整型最小值)进行取反操作,INT_MIN 的取反结果会导致溢出,产生未定义的行为。
        return N >= 0 ? quickMul(x, N): 1.0 / quickMul(x, -N); 
    }
};

2.3 快速幂 + 迭代

思路

由于快速幂的核心理念是每次将上次的结果平方,相当于x(2n) ,但由于在中间乘上额外的x,我们不知道何时触发导致迭代写起来比较麻烦
但是我们仔细观察发现,将初始的x和后面额外乘上的x分开平方
\(x^n=x^{2^{i_0}}\times x^{2^{i_1}}\times\cdots\times x^{2^{i_k}}\)
最后化简可以得到
\(n=2^{i_0}+2^{i_1}+\cdots+2^{i_k}\)
其实就是n的二进制表达式,我们只要n在二进制位为1的值位置
就知道何时要额外乘一个x了

比如像n = 10(1010)是,其实就是2^2 * 2^8
所以我们可以维护一个值专门记录 2^n 的值 x_contributor
当n % 2 == 1时,我们就将结果记录值ans *= x_contributor即可


代码

class Solution {
public:
    double quickMul(double x, long long N) {
        double ans = 1.0;
        double x_contributor = x;
        while(N > 0){
            if(N % 2 == 1) ans *= x_contributor;
            x_contributor *= x_contributor;
            N /= 2.0;
        }
        return ans;
    }

    double myPow(double x, int n) {
        long long N = n;
        return N >= 0? quickMul(x,N):1.0 / quickMul(x,-N);
    }
};
posted @ 2024-01-21 12:53  DawnTraveler  阅读(9)  评论(0编辑  收藏  举报