leetcode: 计算x的幂次函数

题目:

实现 pow(x, n) ,即计算 x 的 n 次幂函数。
示例 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

递归解法

这里采用的思想是分治思想,比如y = xxxxx…x,则如果我们将分为两半,则我们只要计算一半的值,也就是y = x^(n/2),则结果就是yy。通过减少计算的回合数来减少时间复杂度。
这里要思考的是如果n为偶数情况和n为奇数的情况,我们来分析一下
n为偶数: 则我们直接按y = x(n/2)去计算即可,比如24,则通过计算y = 2^2,从而返回结果为yy = 4即可。
n为奇数:这里我们就要拿出一个x出来,此时剩余的个数就为偶数,则继续按偶数去计算,比如25,则我们一样计算y=22,只要再结果的时候,多乘x上去返回即可。即返回结果为y
yx = 44*2 = 32。
这里分治是用递归实现,回到我们的递归思想:
1 递归出口 : 当n=0的时候,返回1
2 递归函数: 入参x和n,计算输入的x和n的幂次方
3 返回值:返回2对应的幂次方
这里的重点是递归函数如何实现,首先,分治,那么我们肯定输入的n一定是2/n,则我们要实现的效果是怎样呢,也就是返回的结果y,我们要的y是x的二分之幂次方的结果。
代码如下:

/**
 * @param x
 * @param n
 * @return
 */
public static  double myPow(double x, int n) {
    // 将n转为长整型,否则当n为负数,转为正数会溢出,所以这里直接另外新建一个函数来完成
    long n1 = n;
    return divide(x,n1);
}

/**
 *  分治算法 :
 *          1. 递归出口,如果是n=0则返回1
 *          2. 如果n小于0的情况,则要将x进行倒数,并且n变为正数
 *          3. 将n分为2部分,则
 *                      当n为偶数时,我们只要计算其中一部分的值为y,则返回的结果为y*y即可
 *                    当n为奇数时,则我们提取出一个x出来,此时又变为偶数,则返回结果为x*y*y即可。
 * @param x
 * @param n
 * @return
 */
private static double divide(double x, long n) {
    // 如果n小于0的情况,则要将x进行倒数,并且n变为正数
        if (n < 0) {
        n = -n;
        x = 1/x;
    }
    // 1. 递归出口,如果是n=0则返回1
    if (n == 0) {
        return 1.0;
    }
    // 2. 递归进行获取结果
    double y = divide(x, n/2);

    // 根据n的奇偶数返回结果集
    if (n % 2 == 0) {
        return y * y;
    }else {
        return x * y * y;
    }
}

图片

非递归方式

我们要思考一下,那么递归就对应与非递归的while语句,那么停止循环的条件是什么呢,依然是n,则依然是判断n是否等于0结束循环。
接下来是while循环内部是怎样的呢?
回顾下我们递归是怎样实现分治的:
当为奇数,则直接相乘;当为偶数,则要再乘一个x;
那么我们再while循环里:
1 判断是否是奇数,是的话,则要多乘x,这里结果为yx
2 将x进行叠乘,让x = x
x (乘到n/2)
3 为了让n一直变到n/2,并且是分治,我们每次让n都做除2操作,也就是对应与右移操作。

/**
 *  非递归方式
 * @param x
 * @param n
 * @return
 */
public static  double myPow1(double x, int n) {
    // 将n转为长整型,否则当n为负数,转为正数会溢出,所以这里直接另外新建一个函数来完成
    long n1 = n;
    double y = 1;

    // 1.  如果n小于0的情况,则要将x进行倒数,并且n变为正数
    if (n1 < 0) {
        // 如果为负数,则转为正,这里不能是n1 = -n,这样如果负数是最小值,转为正会溢出
        n1 = -n1;
        x = 1/x;
    }

    while (n1 != 0) {
        // 非递归方式的话,每次怎样判断n的幂次,
        if ((n1 & 1) != 0 ) {
            // 奇数情况,比如5对应二进制为0101,则0101 & 0001 = 0001,所以不等于0,为奇数
            y = y * x;
        }
        // x进行叠乘
        x = x*x;
        // 这里相当于将n1/2,右移操作
        n1  = n1>>1;
    }

    return y;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值