蓝桥杯冲刺训练营之递归——例2.pow函数

1. 题目

实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn )。

示例 1:

输入:x = 2.00000, n = 10
输出:1024.00000

示例 2:
输入:x = 2.10000, n = 3
输出:9.26100

示例 3:

输入:x = 2.00000, n = -2
输出:0.25000

2. 解题思路

递归问题三步骤:子问题、变量、边界条件

对于求解pow问题的子问题就是n次方等于x*n-1次方,即pow(x, n) = x*pow(x, n-1)

本题的变量就是次数n

注意到n可以为负数,所以边界条件有三个,分别是n = 0,1,-1

通过这样可以编写出简单的递归代码,如下:

class Solution {
public:
    double myPow(double x, int n) {

        
        if (n == 0) return 1;

        if (n == 1) return x;
		
		if (n == -1) return 1/x;

        if (n > 0) return x*myPow(x, n-1);
        else return 1/x * myPow(x, n+1);
    }
};

但是在leetcode上提交会发现stack-overflow堆栈溢出错误,这是由于对于较大的n的时候递归调用了太多的函数,而堆栈内存有限的。
堆栈溢出
那么怎么解决呢?可以采用分治的思想去减少递归调用次数。

分治的思想就是把一个大问题划分为多个小问题求解,小问题如果依然不能解决那么再划分,直到小问题可以直接解决为止。

这题利用分治的思想可以如下思考:

我们想求解x的n次方,那么如果n是偶数,x的n次方是不是就等于x的n/2次方的平方呢?只需要求解出x的n/2次方就能求解得到x的n次方了,这里求解x的n次方就是大问题,求解x的n/2次方就是小问题。同理,在求解x的n/2次方时如果不能直接得到答案,可以继续求解x的n/4, n/8…等子问题。

那么什么样的小问题能直接得到答案呢?这个就是递归的边界条件了,当n = 0,1,-1时能直接得到其答案。

跟据分治思想,编写代码如下:

class Solution {
public:
    double myPow(double x, int n) {
        double ans;

        if (n == 0) return 1;
        if (n == 1) return x;
        if (n == -1) return (1/x);

        if (n>0){

            if (n%2==0){
                ans = myPow(x, n/2)*myPow(x, n/2);
            }
            else{
                ans = x*myPow(x, n/2)*myPow(x, n/2);
            }
        }

        else if (n <0){

            if (n%2==0){
                ans = myPow(x, n/2)*myPow(x, n/2);
            }
            else{
                ans = (1/x)*myPow(x, n/2)*myPow(x, n/2);
            }
        }
        
        return ans;
        
    }
};

我天真的以为这样就结束了,但是提交后发现,超时…
超时

经过冷静的思考后发现,上面的分治函数有大量的重复计算,比如,我在计算 x 4 {x^4} x4时,计算了两遍 x 2 {x^2} x2,而在计算 x 8 {x^8} x8时,里面每一次计 x 4 {x^4} x4都是从头开始计算…于是超时了…

那么怎么避免重复计算呢?我想到了用map去构造一个计算表,每次计算前先判断是否已经计算过,如果计算过就直接调用,否则调用自己递归计算。

最终代码如下:

class Solution {
public:

    map<int, double> table; // 存储结果map表

    double myPow(double x, int n) {
        double ans;

        if (n == 0) return 1;
        if (n == 1) return x;
        if (n == -1) return 1/x;

        if (table.find(n/2) == table.end()){ //当在表中找到结果时才计算新值
            table[n/2] = myPow(x, n/2);
        }

        if (n < 0){

            if (n %2 == 0){
                ans = table[n/2]*table[n/2];
            }
            else if (n%2 != 0){
                ans = (1/x)*table[n/2]*table[n/2]; // n小于0时和大于0主要区别就是这的(1/x)
            }

        }
        else{

            if (n %2 == 0){
                ans = table[n/2]*table[n/2];
            }
            else if (n%2 != 0){
                ans = (x)*table[n/2]*table[n/2];
            }

        }
        
        return ans;
        
    }
};

这次,终于通过啦~~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zh4men9

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值