Leetcode-50: Pow(x,n) O(logn)算法

本文介绍了一种快速计算x^n的方法,通过将指数n转换为二进制形式,并利用位操作来减少乘法次数,实现高效幂运算。文章提供了两种算法实现:递归与非递归,并对比了它们的特点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考了网上一个比较妙的解法。

要注意的地方有:
1) 当n为负数时,可以用1/x^(-n)。但要注意-MIN_VALUE转正时会溢出;

2) while循环内会记录factor=x^(2n)(不管n&0x1是否为1),这样就避免了冗余计算。
3) while循环内,当n&0x1=1时,就让result*=factor。比如说3^10=3^(2^1) * 3^(2^3)。

#include <iostream>

using namespace std;

double myPow(double x, int n) {
    if (n==0) return 1.0;
    bool neg=false;
    if (n<0) {n=-(n+1); neg=true;} //note MIN_MAX may overflow

    double result=1.0;
    double factor=x;
    while(n) {
        if (n & 0x1) result*=factor;
        n=n>>1;     
        factor*=factor;  //record x^(2n)
    }

    if (neg)
       return 1.0/result/x;
    else
       return result;
}

int main()
{
    cout<<myPow(2.0, 10)<<endl;
    cout<<myPow(2.1, 3)<<endl;
    return 0;
}

解法2:递归
 

double myPow(double x, int n) {
  
    if (n == 0) return 1.0;
    double result;
    bool neg=false;
    if (n<0) {
        neg=true;
        n=-(n+1); //note MIN_MAX may overflow
    }
    if (n % 2 == 0) {
        double tmp = myPow(x, n / 2);
        result = tmp * tmp;
    } else {
        double tmp = myPow(x, n / 2);
        result = tmp * tmp * x;
    }
   
    if (neg) result=1.0/result/x;
    return result;
}

递归和非递归的简化版本如下(没有考虑n为负的情况):

//递归
int power(int x, int n) {
    if (n == 0) return 1;
    if (n % 2 == 0) {
        int tmp = power(x, n / 2);
        return tmp * tmp;
    } else {
        int tmp = power(x, n / 2);
        return tmp * tmp * x;
    }
}

//非递归
int power(int x, int n) {
    int ans = 1, base = x;
    while (n != 0) {
        if (n % 2 == 1) {
            ans *= base;
        }
        base *= base;
        n = n / 2;
    }
    return ans;
}

怎么来理解这个非递归算法呢?实际上我觉得这个非递归算法和递归算法并不是一一对应的。它是基于这么一个事实:即x ^ n 就是当n写成2进制时,把它的二进制位数上是1的那些数找出来,算出其对应的x次方,然后求其全部乘积即可。打个比方: n = 11,写成2进制是1011,对应11=1+2+8(注意不是index 0,1,3)。所以x^11=x^1*x^2*x^8,即我们求出x, x ^ 2, x^ 8,然后全部相乘即可。这也就是为什么ans *= base只是当n 为奇数才执行(因为我们只需要找出2进制里面那些是1的数)。但我们不管n是否为奇数,都要执行base*=base操作,这样,就可以求下一个2^n的值。

三刷:利用x^n = (1/x)^(-n)就可以了。

class Solution {
public:
    /**
     * @param x: the base number
     * @param n: the power number
     * @return: the result
     */
    double myPow(double x, int n) {
        long long m = n;
        if (m < 0) {
            m = -m;
            x = 1/x;
        }
        double res = 1.0, prod = x;
        while (m) {
            if (m & 0x1) res *= prod;
            m >>= 1;
            prod *= prod;
        }
        return res;
    }
};

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值