递归(快速幂)(5)

https://blog.csdn.net/2601_95366422/article/details/159202641

上节课链接

一.题目

50. Pow(x, n) - 力扣(LeetCode)

二.思路讲解

2.1 找到递归

本题要求实现 xn 次幂 。我们可以通过递归分治 来高效计算。例如,求 216 次方,可以分解为 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),它计算 xn 次幂。在递归过程中:

  • 先递归求出 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 == 0n <= 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 的奇偶性决定如何组合。这个函数的返回值就是 xn 次幂。

三、递归终止条件

递归的终止条件是当 n == 0 时,任何数的 0 次幂都等于 1.0 ,直接返回 1.0。这是递归的基础情况,也是递归能够层层返回的关键。

四、递归步骤分解

对于 n > 0 的情况,递归步骤如下:

  1. 递归获取子结果 调用 myPow(x, n/2) 得到 x^(n/2) 的值,记为 tmp。注意这里 myPow 会再次进入主函数,但由于 n/2 是正数,它会再次调用 pow,从而形成递归链。这一步骤我们无需关心内部细节,只需相信它能正确返回子结果。

  2. 根据奇偶性组合结果

    • 如果 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 类型,直接相乘即可,无需特殊处理。。

相关推荐
海石5 小时前
【JS击败90%】前缀和+定长滑动窗口
算法·leetcode
hold?fish:palm5 小时前
从源码到可执行文件:C++程序的编译过程
开发语言·c++
Tisfy6 小时前
LeetCode 2685.统计完全连通分量的数量:DFS求每个连通块的边点数
算法·leetcode·深度优先··题解·连通图·全连通分量
海石6 小时前
1次遍历,空间复杂度击败100%,时间复杂度击败85%
算法·leetcode
lingran__6 小时前
C++_STL简介
开发语言·c++
南国韭菜6 小时前
【无标题】
c++·qt
L歪歪君6 小时前
Apache Doris全链路性能优化实战指南:从架构设计到生产落地
java·开发语言·算法
m0_466525296 小时前
从“算法内卷”到“可信易用” 东软多模态医学人工智能平台开启无代码科研新时代
人工智能·算法
没用的阿_吉7 小时前
vs2022offline 生成
c++
码少女7 小时前
数据结构——冒泡排序及优化
数据结构·算法·排序算法