0010 Pow(x,n)

Pow(x,n)

编号:0010

试题来源:leetcode

题目描述

实现 p o w ( x , n ) pow(x,n) pow(x,n),即计算 x x x n n n次幂

其中 − 100.0 < x < 100.0 -100.0 < x<100.0 100.0<x<100.0

n n n是32位有符号整数,其数值范围是 [ − 2 31 , 2 31 − 1 ] [-2^{31},2^{31}-1] [231,2311],也就是c++int的取值范围

示例

  • 示例1:

    在这里插入图片描述

  • 示例2:

在这里插入图片描述

  • 示例3:

在这里插入图片描述

解答算法

递归(我的解法)

算法思路

对于底数 x x x来说,有特殊情况 x = = 1 x==1 x==1,此时不用判断 n n n直接输出 0 0 0就好。

对于指数 n n n来说,当 n = = 0 n==0 n==0的时候,不适用于递归表达式,直接输出 1 1 1就好

对于一般情况来说, x n x^n xn有两种可能,一种是 n n n是奇数,另一种是 n n n是偶数,当 n n n是偶数的时候,显然 x n = x n 2 ∗ x n 2 x^{n} = x^{\frac{n}{2}}*x^{\frac{n}{2}} xn=x2nx2n这里面,显然把 x n 2 x^{\frac{n}{2}} x2n利用了两次,这样的话,就相对于逐个递乘减少了一般的工作量;当 n n n时偶数的时候, x n = x n 2 ∗ x n 2 ∗ x x^{n} = x^{\frac{n}{2}}*x^{\frac{n}{2}} * x xn=x2nx2nx只是在之前的基础上多乘了一个x,计算步骤也是很小的。

然后递归的终止条件就是 n = = 1 n==1 n==1,此时,只要返回 x x x就好。

当计算 n < 0 n<0 n<0的时候,我用的是 x n = 1 x − n x^{n} = \frac{1}{x^{-n}} xn=xn1,但是这里存在越界的可能,对于 − 2 31 -2^{31} 231来说,其相反数 2 31 2^{31} 231不能用int类型表示,因此我把式子改写成了 x n = 1 x − n − 1 ∗ x x^n=\frac{1}{x^{-n-1}*x} xn=xn1x1这样就避免了 − n -n n越界的可能性。

实现代码

class Solution {
public:
    double myPow(double x, int n) {
        if (x == 1)   //当底数为1的时候,直接输出1
            return 1;
        if (n < 0)    //当指数小于0的时候,先转换成指数大于0的情况
            return 1 / (x * myPow(x, -(n + 1)));
        if (n == 0)   //当指数为0的时候,直接输出1
            return 1; 
        if (n == 1)  //当指数为1的时候,递归终止
            return x;
        double result = myPow(x, n / 2);  //递归调用
        if (n % 2 == 0)  //偶数和结束分开讨论
            return result * result;
        if (n % 2 == 1)
            return result * result * x;
        return 0;  //这个是因为程序要求一定要有返回值,所以加上的,无意义
    }
};

复杂度分析

  • 时间复杂度:每一次递归仅进行了一次操作,一共进行了 l o g n logn logn次递归,因此时间复杂度 O ( l o g n ) O(logn) O(logn)
  • 空间复杂度:整个过程中用到的空间是递归用到的栈空间,深度应当是 l o g n logn logn,因此空间复杂度 O ( l o g n ) O(logn) O(logn)

这是我自己第一次两个100%击败,有点意思—__—

递归(官方解答)

算法思路和复杂度分析和我的一样,不列举了。

代码实现

class Solution {
public:
    double quickMul(double x, long long N) {  //指数变成N,避免了溢出问题
        if (N == 0) {  //指数为0的情况
            return 1.0;
        }
        double y = quickMul(x, N / 2);    //递归调用
        return N % 2 == 0 ? y * y : y * y * x;  //这个对奇偶的利用有点简洁
    }

    double myPow(double x, int n) {
        long long N = n;
        return N >= 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N); //对正负的利用
    }
};

三目运算符真好使

迭代(官方解答)

算法思路

迭代思路用到了整数的二进制表示, n n n是一个十进制整数,它一定可以被转化成一个二进制数 i k i k − 1 … i 0 i_ki_{k-1}\dotso i_0 ikik1i0,那么 n = 2 i 0 + 2 i 1 + … + 2 i k n=2^{i_0}+2^{i_1}+\dotso + 2^{i_k} n=2i0+2i1++2ik,因此 x n = x 2 i 0 ∗ … ∗ x 2 i k x^n=x^{2^{i_0}}*\dotso *x^{2^{i_k}} xn=x2i0x2ik,因此只要知道了二进制数,可以求解其对应的 x n x^n xn

代码实现

class Solution {
public:
    double quickMul(double x, long long N) {
        double ans = 1.0;
        // 贡献的初始值为 x
        double x_contribute = x;
        // 在对 N 进行二进制拆分的同时计算答案
        while (N > 0) {
            if (N % 2 == 1) {
                // 如果 N 二进制表示的最低位为 1,那么需要计入贡献
                ans *= x_contribute;
            }
            // 将贡献不断地平方
            x_contribute *= x_contribute;
            // 舍弃 N 二进制表示的最低位,这样我们每次只要判断最低位即可
            N /= 2;
        }
        return ans;
    }

    double myPow(double x, int n) {
        long long N = n;
        return N >= 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N);
    }
};

复杂度分析

  • 时间复杂度:整个过程中进行了 l o g n logn logn层循环,因此时间复杂度为 O ( l o g n ) O(logn) O(logn)
  • 空间复杂度:显然 O ( 1 ) O(1) O(1)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值