LeetCode刷题之路-剑指 Offer 16. 数值的整数次方

LeetCode刷题之路-剑指 Offer 16. 数值的整数次方

题目介绍

实现 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-2 = 1/22 = 1/4 = 0.25

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zhi-de-zheng-shu-ci-fang-lcof

解题思路

  1. 这道算幂次方的题和递归算阶乘的有点像,应该可以直接递归。看一下数据范围,n可以去负数,那这样的话,递归结束条件不太好写。可以先预处理一下,将负数的幂次方转换成正数的幂次方,即x^(-n) => (1/x)^n。代码如下:

    class Solution {
        public double pow(double x, int n) {
            if(n == 1) // 递归结束条件,写n = 0或者 n = 1都可以
                return x;
            return x * myPow(x, n - 1); // 这个地方当n较大时,就爆栈了,报EE错误。
        }
        public double myPow(double x, int n) {
            if(n == 0)
                return 1;
            if(n < 0) { // 预处理
                n = -n;
                x = 1 / x;
            }
            return pow(x, n);
        }
    }
    
  2. 递归爆栈了,那我改成迭代吧,直接累乘可以吧。代码如下:

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

    很遗憾,这次TLE了,2^31次方的复杂度足够超时了。

  3. 再改进一下,可以使用快速幂的方法。当n为偶数时,x^n = [x^(n/2)] ^2,也就是先求出x的n/2的幂次方,然后再对其求二次方就好了。这样的话就相当于少算了一次x的n/2的幂次方,利用了之前运算的结果。那么当n为奇数时呢,转换一下,将其转成偶数就好了,也就是提出一个x,那么n-1不就是偶数了吗。详细步骤如下:

    • 当n == 0时,返回1;
    • 当n < 0时,预处理=>(n = -n; x = 1 / x);
    • 当n为奇数时,x * pow(x,n - 1);
    • 当n为偶数时,pow(x,n / 2) * pow(x,n / 2
    class Solution {
        public double myPow(double x, int n) {
            if(n == 0)
                return 1.0;
            else if(n < 0)
                return (1 / x) * myPow(1 / x, -(n + 1)); // // 当 n = -2147483648时执行n=−n 会越界,直接提取一个1/x即可
            else if((n & 1) == 0) {
                double tmp = myPow(x, n / 2);
                return tmp * tmp;
            } else{
                return x * myPow(x, n - 1); 
            }
        }
    }
    

结语

该题是快速幂的典型应用题,它实际上思想上也是运用了记录减少重复计算的次数,也就是减少了重复子问题的计算。在写代码,注意的点还是挺多的,比如n<0时的预处理,n为奇数时的转化以及当n为Integer的最小值时的防溢出处理。这些细节都注意到,才能编写出合格的代码。

最后,希望此文章能给大家带来收获,谢谢大家!

posted @ 2021-05-16 23:29  己平事  阅读(74)  评论(0编辑  收藏  举报