一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情
力扣题目链接
实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,x^n )
示例 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/2^2 = 1/4 = 0.25
提示:
- -100.0 < x < 100.0
- -2^31 <= n <= 2^31-1
- -10^4 <= x^n <= 10^4
解题过程
第一眼看到题时,觉得题也不难,心想不就是判断加循环嘛
我的思路是:判断n的数值,再进行循环 先定义一个 sum 变量,用来存放结果值
- 当n == 0时,x无论是多少,结果值都为1
- 当n > 0时,需要再进行判断,当n > 0且n < 2时,结果值都为x,反之,当n >= 2时,我们就要用循环了,循环体里面放的是 sum = x * sum;
- 当n < 0时,步骤其实跟第二条一样,只不过结果值需要倒转即可
代码:
class Solution {
public double myPow(double x, int n) {
double sum = 0;
sum = x;
if (n == 0) {
return 1;
}else if (n > 0) {
if (n < 2 && n > 0) {
return x;
}else if (n >= 2) {
for (int i = 1; i < n; i++) {
x = x*sum;
}
}
}else {
for (int i = n; i < -1;i++) {
x = x*sum;
}
x = 1/x;
}
return x;
}
}
当我信心满满提交代码,觉得一定能过时,系统却提示我超出时间限制
看来不能这样写,经过了两天的学习,我最终终于掌握了这道题
思路:(分治算法)
在网上学习的过程中,我发现了一种算法,名字叫分治算法
顾名思义,分治算法由“分”和“治”组成,它主要包括三个过程
- 划分:将原问题划分为规模较小的子问题,子问题相互独立,与原问题形式相同
- 解题:递归的求解划分之后的子问题。
- 合并:这一步非必须。有些问题涉及合并子问题的解,将子问题的解合并成原问题的解。有的问题则不需要,只是求出子问题的解即可 举例来说: 二分查找就是分治算法的一种应用,每次取中间值进行判断,每次取一半
说白了就是先找到拆分到最小的问题怎么解,然后再瞅瞅随着问题规模增大点问题怎么解,最后就是找到递归函数,码出递归代码即可
我们先回归到题目中,n会有三种可能,要么是负数,是正数又分为奇数,或是偶数
这样列完可能后,解题步骤就很明确了
-
划分: n为偶数时,x^n可以转化为 x^n/2 与 x^n/2 的相乘,x^n/2 就可以转化为x^n/4与x^n/4的相乘,n一直除下去,直到n为1为止
n为奇数时,我们只需取出一个x来,剩下的n就是一个偶数,再用上面的逻辑进行转换,最后记得要把取出的这个x与结果相乘
n为负数时,更简单,(-n)就是正数,x^(n)可以转为x^(-n),再按照上面的逻辑进行转换,结果取倒数即可
-
求解: 求划分后的子问题的解
-
合并 将子问题的解一步步向上合并
这里我画了图,大家可以看图来理解我上面的话
1.以x = 2.00,n = 10 来说明
2.以x = 2.00,n = -10 来说明
代码:(Java实现)
public static double Pow(double x, int n) {
if (n == 0) {
return 1;
}
if (n == 1 || x == 1.0) {
return x;
}
if (n < 0) {
return 1 / x * Pow(1/x,-(n+1));
}
int a = n/2;
int b = n%2;
if (b == 0) {
Pow(x * x,a);
}else {
x * Pow(x * x,a);
}
输出分析:
复杂度分析:
此解法需要计算 x 的 n 次方,x 的 n/2 次方,x 的 n/4 次方,...,x 的 1 次方,所以时间复杂度为 O(logn)
虽然分治算法没有直接分配额外的数组空间,但是在递归过程中调用了额外的栈空间,分治算法相当于每次将当前问题拆成了两部分,n 在变为 1 之前需要进行 O(logn) 次递归,所以空间复杂度也为 O(logn)