首先这是题目
Implement pow(x, n), which calculates x raised to the power n (xn).
Example 1:
Input: 2.00000, 10
Output: 1024.00000
Example 2:
Input: 2.10000, 3
Output: 9.26100
Example 3:
Input: 2.00000, -2
Output: 0.25000
Explanation: 2-2 = 1/22 = 1/4 = 0.25
Note:
-100.0 < x < 100.0
n is a 32-bit signed integer, within the range [−231, 231 − 1]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/powx-n
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
这个问题其实就是自己写一个Pow函数,来计算x的n次幂
第一时间我想到的是二分法
假设要求
2
48
=
2
24
∗
2
24
=
2
12
∗
2
12
∗
2
12
∗
2
12
=
2
6
∗
2
6
∗
2
6
∗
2
6
∗
2
6
∗
2
6
∗
2
6
∗
2
6
=
2
3
∗
2
3
∗
2
3
∗
2
3
∗
2
3
∗
2
3
∗
2
3
∗
2
3
∗
2
3
∗
2
3
∗
2
3
∗
2
3
∗
2
3
∗
2
3
∗
2
3
∗
2
3
2^{48}=2^{24}*2^{24}=2^{12}*2^{12}*2^{12}*2^{12}=2^{6}*2^{6}*2^{6}*2^{6}*2^{6}*2^{6}*2^{6}*2^{6}=2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}*2^{3}
248=224∗224=212∗212∗212∗212=26∗26∗26∗26∗26∗26∗26∗26=23∗23∗23∗23∗23∗23∗23∗23∗23∗23∗23∗23∗23∗23∗23∗23…
因为我还是更加熟悉c#/Java所以先选择了Java
import java.util.Scanner;
class Main{
public static void main(String[] args) {
double x;
int n;
Scanner sc = new Scanner(System.in);
System.out.println("Pls input x");
x = sc.nextDouble();
System.out.println("Pls input n");
n = sc.nextInt();
System.out.println(myPow(x, n));
}
static double myPow(double x, int n) {
int N = n;
if (n == 0)
return 1;
return N > 0 ? CalPow(x, N) : 1 / CalPow(x, -N);
}
static double CalPow(double x, int N)
{
if (N == 1)
return x;
int n = N / 2;
if (N % 2 != 0)
{
return x * CalPow(x, n) * CalPow(x, n);
}
return CalPow(x, n) * CalPow(x, n);
}
}
一跑发现有溢出了,大晚上脑子有点懵,还以为是double溢出,但是浮点数是以 符号 指数 小数 来储存的,不太可能溢出啊。后来看了看大佬们的题解,才发现是在N取-128的时候变成正数造成的溢出
所以还是得谨慎一点才行
修改之后
import java.util.Scanner;
class Main{
public static void main(String[] args) {
double x;
int n;
Scanner sc = new Scanner(System.in);
System.out.println("Pls input x");
x = sc.nextDouble();
System.out.println("Pls input n");
n = sc.nextInt();
System.out.println(myPow(x, n));
}
static double myPow(double x, int n) {
long N = n;
if (n == 0)
return 1;
return N > 0 ? CalPow(x, N) : 1 / CalPow(x, -N);
}
static double CalPow(double x, long N)
{
if (N == 1)
return x;
int n = (int)N / 2;
if (N % 2 != 0)
{
return x * CalPow(x, n) * CalPow(x, n);
}
return CalPow(x, n) * CalPow(x, n);
}
}
舒服多了,可是新的问题又产生了。对,就是该死的超时,递归的时候我每次都要再重新算一遍结果,然后它就超时了
import java.util.Scanner;
class Main{
public static void main(String[] args) {
double x;
int n;
Scanner sc = new Scanner(System.in);
System.out.println("Pls input x");
x = sc.nextDouble();
System.out.println("Pls input n");
n = sc.nextInt();
System.out.println(myPow(x, n));
}
static double myPow(double x, int n) {
long N = n;
if (n == 0)
return 1;
return N > 0 ? CalPow(x, N) : 1 / CalPow(x, -N);
}
static double CalPow(double x, long N)
{
if (N == 1)
return x;
double num = CalPow(x, N / 2);
if (N % 2 != 0)
{
return x * num * num;
}
return num * num;
}
}
OK,问题解决!
然后是官方给出的二进制解法
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);
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/powx-n/solution/powx-n-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
嚯,真是妙啊。
因为每个
x
n
x^n
xn都会被拆成
x
n
/
2
∗
x
n
/
2
x^{n/2}*x^{n/2}
xn/2∗xn/2或者是
x
n
/
2
∗
x
n
/
2
∗
x
x^{n/2}*x^{n/2}*x
xn/2∗xn/2∗x
假设我们要求
x
77
x^{77}
x77
那么
x
→
x
2
→
x
4
→
x
9
→
x
19
→
x
38
→
x
77
x \rightarrow x^{2} \rightarrow x^{4} \rightarrow x^{9} \rightarrow x^{19} \rightarrow x^{38} \rightarrow x^{77}
x→x2→x4→x9→x19→x38→x77
其中在
x
77
x^{77}
x77、
x
19
x^{19}
x19、
x
9
x^{9}
x9在拆分的时候要多拆一个x
x
77
x^{77}
x77被拆开时,需要多乘一个
x
x
x
x
19
x^{19}
x19被拆开时,需要多乘四个
x
x
x,就有
2
2
=
4
2^{2}=4
22=4
x
9
x^{9}
x9被拆开时,需要多乘八个
x
x
x,就有
2
2
2
=
8
2^{2^2}=8
222=8
然后最初的
x
x
x被拆了6次,那么就有
2
6
=
64
2^6=64
26=64
将它们全部相乘
x
∗
x
4
∗
x
8
∗
x
64
x*x^4*x^8*x^{64}
x∗x4∗x8∗x64结果正好为
x
77
x^{77}
x77
而其中的1,4,8,64 恰好又是77的二进制数
(
1001101
)
2
(1001101)_2
(1001101)2中的每个1
总结
这个题自己犯错的主要问题就是没有考虑全面,多注意一些小细节,以及多思考怎样才能计算次数更少才行,一开始return 函数*函数那就要多算很多遍。
一些问题可以尝试从二进制下手,只要找出其中的规律,解决问题所需的时间和空间可能会大大减少。