https://blog.csdn.net/2601_95366422/article/details/159202641
上节课链接
一.题目

二.思路讲解
2.1 找到递归
本题要求实现 x 的 n 次幂 。我们可以通过递归分治 来高效计算。例如,求 2 的 16 次方,可以分解为 2^8 * 2^8,而 2^8 又可以分解为 2^4 * 2^4,如此反复,直到 2^0 = 1。这就是典型的快速幂 思想。但需要注意,当 n 为奇数时,比如 2^5,可以分解为 2^2 * 2^2 * 2,即多乘一个 x。因此,递归的规律就是:每次将指数减半,根据奇偶性决定是否多乘一次底数。
2.2 子问题解决
明确了递归规律,子问题的解决就清晰了:我们定义一个递归函数 myPow(x, n),它计算 x 的 n 次幂。在递归过程中:
-
先递归求出
x^(n/2)的值,记为half。 -
如果
n是偶数,则结果为half * half。 -
如果
n是奇数,则结果为half * half * x。
2.3 递归的终止条件
递归的终止条件是当 n == 0 时,任何数的 0 次幂都等于 1 ,直接返回 1。这是递归的基础情况,也是递归能够结束的关键。
2.4 细节问题
-
负指数处理 :如果
n为负数,我们可以先计算x的|n|次幂,然后取倒数,即1 / myPow(x, -n)。但这里有一个边界陷阱 :当n为 最小负整数 (如-2^31)时,取相反数会超出int范围,导致溢出。因此,需要将n转换为long long类型来处理。 -
底数为 0 的情况 :当
x == 0且n <= 0时,需要处理除零异常,但题目通常保证输入有效。 -
精度问题 :由于结果是浮点数,直接递归计算即可,注意使用
double类型。
三.代码演示
cpp
class Solution
{
public:
double myPow(double x, int n)
{
long long t = (long long)n;//避免最小负数不能转成正数
if(n < 0)
{
return 1 / pow(x,-t);
}
else
return pow(x,t);
}
double pow(double x,long long n)
{
if(n == 0)
return 1.0;
double tmp = myPow(x,n/2);//获取下一次值
return n % 2 == 0 ? tmp * tmp : tmp * tmp * x;
}
};
四.代码讲解
一、主函数处理负指数
在公开接口 myPow 中,首先需要处理指数 n 可能为负数的情况。由于负指数运算等价于正指数结果的倒数,因此我们将 n 转换为 long long 类型 t,以避免最小负数(如 -2^31)取相反数时溢出。若 n < 0,则返回 1 / pow(x, -t),即先计算正指数的幂,再取倒数;否则直接调用 pow(x, t) 计算正指数幂。这样,主函数负责符号处理 和溢出保护,将问题统一转化为正指数计算。
二、递归函数设计
辅助函数 pow(double x, long long n) 专门用于计算 x 的非负整数次幂。它采用递归分治 的思想:每次将指数 n 除以 2,先求出 x^(n/2) 的值,再根据 n 的奇偶性决定如何组合。这个函数的返回值就是 x 的 n 次幂。
三、递归终止条件
递归的终止条件是当 n == 0 时,任何数的 0 次幂都等于 1.0 ,直接返回 1.0。这是递归的基础情况,也是递归能够层层返回的关键。
四、递归步骤分解
对于 n > 0 的情况,递归步骤如下:
-
递归获取子结果 调用
myPow(x, n/2)得到x^(n/2)的值,记为tmp。注意这里myPow会再次进入主函数,但由于n/2是正数,它会再次调用pow,从而形成递归链。这一步骤我们无需关心内部细节,只需相信它能正确返回子结果。 -
根据奇偶性组合结果
-
如果
n是偶数,则x^n = tmp * tmp,直接返回两者的乘积。 -
如果
n是奇数,则x^n = tmp * tmp * x,即再多乘一个x。
-
这样,每次递归都将指数减半,时间复杂度为 O(log n)。
五、关键细节
-
类型转换与溢出保护 :将
int类型的n转换为long long后再取相反数,避免了最小负数溢出问题。 -
递归的信任 :在
pow函数中调用myPow时,我们相信它能正确处理子问题,尽管两者互相调用,但逻辑上是自洽的。 -
奇偶判断 :通过
n % 2判断奇偶性,决定是否多乘一次x。 -
终止条件的准确性 :当
n == 0时直接返回1.0,这是递归的出口。 -
浮点数运算 :结果使用
double类型,直接相乘即可,无需特殊处理。。