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
解题思路
-
这道算幂次方的题和递归算阶乘的有点像,应该可以直接递归。看一下数据范围,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); } }
-
递归爆栈了,那我改成迭代吧,直接累乘可以吧。代码如下:
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次方的复杂度足够超时了。
-
再改进一下,可以使用快速幂的方法。当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的最小值时的防溢出处理。这些细节都注意到,才能编写出合格的代码。
最后,希望此文章能给大家带来收获,谢谢大家!