递归算法之快速幂(Exponentiation by Squaring)详细解读

快速幂(Exponentiation by Squaring)是一种用于快速计算大整数的幂次的算法。传统的幂运算需要进行 nnn 次乘法,而快速幂通过将幂次指数二分,减少了所需的乘法次数,使得计算复杂度从 O(n) 降低到 O(log⁡n)。它广泛应用于大整数运算、模幂运算(尤其是在密码学领域),以及其他需要高效幂运算的地方。

1. 基本思想

快速幂的基本思想是利用指数的二进制性质,将大规模的幂运算转化为多个小规模的幂运算。通过将指数的幂次按二分递归或迭代来处理,可以有效减少运算次数。

对于给定的底数 x 和幂次 n,我们希望计算 的值。使用以下规则来递归地进行幂运算:

  • 若 n 为偶数,则:

                ​​​​​​​        ​​​​​​​        ​​​​​​​        

  • 若 n 为奇数,则:

        ​​​​​​​        ​​​​​​​        

通过上述方法,每次将指数 n 减半,最终使得幂次计算变得更加高效。

2. 算法过程

快速幂算法有两种实现方式:递归迭代。两者的思路基本一致,但实现方式不同。

2.1 递归实现

递归实现利用了函数调用栈,在每次递归调用时将问题规模减半,最终返回结果。

递归实现的代码:
public class FastPower {

    // 递归实现的快速幂
    public static long fastPower(long x, long n) {
        if (n == 0) {
            return 1;  // 任何数的0次幂为1
        }

        long half = fastPower(x, n / 2);  // 计算 x^(n/2)
        
        if (n % 2 == 0) {
            return half * half;  // 如果n是偶数,结果是 half^2
        } else {
            return half * half * x;  // 如果n是奇数,结果是 half^2 * x
        }
    }

    public static void main(String[] args) {
        long base = 2;
        long exponent = 10;
        long result = fastPower(base, exponent);
        System.out.println(base + "^" + exponent + " = " + result);  // 输出 2^10 = 1024
    }
}
代码解析:
  • 当幂次 n=0 时,直接返回 1,这是幂运算的基础情况。
  • 通过递归调用 fastPower(x, n / 2),将幂次 n 不断减半。
  • 根据 n 的奇偶性,选择是否乘以额外的底数 x。
  • 每次递归调用使得问题规模减半,最终的递归深度为 O(log⁡n)。
2.2 迭代实现

迭代实现不使用递归,而是通过循环迭代来完成幂运算,避免了递归带来的函数调用开销。

迭代实现的代码:
public class FastPowerIterative {

    // 迭代实现的快速幂
    public static long fastPowerIterative(long x, long n) {
        long result = 1;  // 初始化结果为1
        long base = x;  // 将底数存储在base中
        while (n > 0) {
            if (n % 2 == 1) {  // 如果n是奇数
                result *= base;  // 乘上当前的base
            }
            base *= base;  // 每次将base平方
            n /= 2;  // 幂次减半
        }
        return result;
    }

    public static void main(String[] args) {
        long base = 2;
        long exponent = 10;
        long result = fastPowerIterative(base, exponent);
        System.out.println(base + "^" + exponent + " = " + result);  // 输出 2^10 = 1024
    }
}
代码解析:
  • 初始时,result 被设为 1,表示幂运算的累积结果。
  • base 保存当前的底数,初始值为 xxx。
  • 每次判断指数 nnn 的奇偶性,若为奇数,将当前的底数 basebasebase 累乘到结果 result 中。
  • 无论指数是否为奇数,每次都将底数平方,并将指数减半。
  • 迭代完成后,最终结果保存在 result 中。

3. 快速幂的时间复杂度

快速幂将指数 n 不断二分,问题规模减小得非常快。每次运算的成本为常数时间,因此其时间复杂度为 O(\log n),相比于直接的幂运算 O(n) 效率大大提高。

  • 时间复杂度:O(log⁡n)
  • 空间复杂度
    • 递归版本的空间复杂度为 O(log⁡n)(递归深度)。
    • 迭代版本的空间复杂度为 O(1)(常数额外空间)。

4. 模幂运算

快速幂常常用于处理 模幂运算,即计算。在许多应用中,幂运算的结果可能非常大,无法直接存储,因此需要对结果取模。例如,密码学中的 RSA 算法就需要大量的模幂运算。

在快速幂的基础上,我们可以通过在每次乘法运算后取模来确保结果不会溢出。

模幂运算的实现:
public class ModularExponentiation {

    // 快速幂的模运算实现
    public static long modPower(long x, long n, long mod) {
        long result = 1;
        long base = x % mod;  // 先对base取模
        
        while (n > 0) {
            if (n % 2 == 1) {
                result = (result * base) % mod;  // 累积结果后取模
            }
            base = (base * base) % mod;  // 将base平方后取模
            n /= 2;
        }
        return result;
    }

    public static void main(String[] args) {
        long base = 2;
        long exponent = 10;
        long mod = 1000;
        long result = modPower(base, exponent, mod);
        System.out.println(base + "^" + exponent + " % " + mod + " = " + result);  // 输出 2^10 % 1000 = 24
    }
}
代码解析:
  • 每次乘法运算后都对结果 result 和底数 base 取模,防止结果溢出。
  • 模运算的性质保证了​​​​​​​(a×b)%m=((a%m)×(b%m))%m,从而可以保持结果在合理范围内。

5. 快速幂的应用场景

5.1 密码学

快速幂在密码学中有重要应用,特别是在 RSADiffie-Hellman 密钥交换中,涉及大量大数的幂模运算。快速幂能够快速计算出模幂结果,保证算法的效率。

5.2 矩阵幂

快速幂同样可以用于矩阵的幂运算。矩阵幂运算可以用于解决一些动态规划问题(例如斐波那契数列的快速求解),通过将矩阵幂次方转化为快速幂问题,极大提升算法效率。

6. 总结

快速幂是一种高效的幂运算算法,它通过将幂次不断二分,降低了运算次数,从 O(n) 优化到了 O(log⁡n)。该算法有两种实现方式:递归和迭代。快速幂广泛应用于各种需要高效幂运算的场景,尤其是大数运算和模幂运算中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/899307.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【图论】(五)最短路径算法(D / BF / SPFA / F / A*)

最短路径算法(D / BF / SPFA / F / A*) 1. 最短路径之dijkstra(D算法)思路模拟过程程序实现拓展 2. dijkstra算法堆优化思路程序实现 3. Bellman_ford 算法(BF算法)松弛模拟过程拓展 4. Bellman_ford 队列优…

数据结构-B树和B+树

一、B树 一个节点包含多个key-value值 假设一棵B树由M个参数构建,我们将其称为M阶B树 每个节点最多有M-1个key-value值,并且key值升序排列,每个节点最多能有M个叉 1.1 分类 二节点 三节点 四节点 五节点 key: 给每一个文件进行标号&…

关于iPhone 16 Pro评测视频评论区特征的多维度分析

1.项目背景 随着智能手机的迅速发展,消费者在选择新设备时越来越依赖于网络评价和用户反馈,B站作为中国领先的视频分享平台,聚集了大量科技评测内容,其中UP主的评论区成为用户讨论和交流的重要场所,特别是在iPhone 16…

论文阅读:Guided Linear Upsampling

今天介绍一篇有趣的文章,Guided Linear Upsampling,基于引导的线性上采样,这是发表在 ACM transaction on Graphic 的一篇工作。 Abstract 引导上采样是加速高分辨率图像处理的一种有效方法。在本文中,文章作者提出了一种简单而…

Jetpack架构组件_LiveData组件

1.LiveData初识 LiveData:ViewModel管理要展示的数据(VM层类似于原MVP中的P层),处理业务逻辑,比如调用服务器的登陆接口业务。通过LiveData观察者模式,只要数据的值发生了改变,就会自动通知VIEW层&#xf…

excel判断某一列(A列)中的数据是否在另一列(B列)中

如B列如果有7个元素,在A列右边的空白列中,输入如下公式: COUNTIF($B$1:$B$7,A1), 其中,$B$1:$B$7代表A列中的所有数据即绝对范围,A1代表B列中的一个单元格.

Opensearch集群部署【docker、服务器、Helm多种部署方式】

操作系统兼容性 我们建议在 Red Hat Enterprise Linux (RHEL) 或使用systemd的基于 Debian 的 Linux 发行版上安装 OpenSearch ,例如 CentOS、Amazon Linux 2 和 Ubuntu Long-Term Support (LTS)。OpenSearch 应该适用于大多数 Linux 发行版,但我们只测…

ctfshow-文件上传-151-161

CTFshow文件上传 PHP文件上传:1、代码思路 黑名单是设置不能通过的用户,黑名单以外的用户都能通过。 phtml、pht、php3、php4、php5后缀都会按做php文件执行,且不在黑名单内。 2、绕过 找漏网之鱼:cer、php3、php4、phtml等。 大小写绕…

react 基础学习笔记

1.react 语法 ①数据渲染 函数组件将HTML结构直接写在函数的返回值中 JSX只能有一个根元素 JSX插值写法 插值可以使用的位置 1.标签内容; 2.标签属性 JSX 条件渲染:三目运算符; JSX根据数据进行列表渲染:map()方法&#x…

elementUI进度条el-progress不显示白色

效果图 通过设置百分比为100,动态修改进度条的宽度完成 <template><div class"myProgressBox"><div class"index">{{ index }}</div><div class"typeTitle">{{ typeTitle }}</div><div class"twoP…

Java求最大值 C语言局部变量 全局变量

1. public static void main(String[] args) {int[] arr {25, 24, 12, 98, 36, 45};int max arr[0];//不能写0for (int i 1; i < arr.length; i) {if (arr[i] > max) {max arr[i];}}System.out.println(max);} }//循环为零&#xff0c;降低效率&#xff08;就是自己…

autMan框架对接Kook机器人

一、创建kook机器人 KOOK 二、获取机器人token 三、填写autMan参数并重启 四、将机器人加入服务器 五、效果图 回复

技术成神之路:设计模式(二十二)命令模式

介绍 命令模式&#xff08;Command Pattern&#xff09;是一种行为设计模式&#xff0c;允许将请求&#xff08;命令&#xff09;封装为对象&#xff0c;从而使您可以使用不同的请求、队列或记录请求日志&#xff0c;以及支持可撤销操作。 1. 定义 命令模式将一个请求封装为一个…

Qt中使用线程之QRunnable

1、自定义1个子类继承自QRunnable 2、重写run方法&#xff0c;编写子线程的业务逻辑 3、使用QThreadPool的全局方法来开启这个线程 4、线程的回收不需要关注&#xff0c;由QThreadPool处理 5、缺点&#xff1a;无法使用信号槽机制 6、适合一些不需要和主线程通信的耗时的任…

JVM 加载 class 文件的原理机制

JVM 加载 class 文件的原理机制 JVM&#xff08;Java虚拟机&#xff09;是一个可以执行Java字节码的虚拟机。它负责执行Java应用程序和应用程序的扩展&#xff0c;如Java库和框架。 文章目录 JVM 加载 class 文件的原理机制1. JVM1.1 类加载器1.2 魔数1.3 元空间 2. 类加载2.1 …

一篇文章快速认识 YOLO11 | 目标检测 | 模型训练 | 自定义数据集

本文分享YOLO11的目标检测&#xff0c;主要内容是自定义数据集、数据标注、标签格式转换、模型训练、模型推理等。 目录 1、数据标注 2、Labelme的json转为YOLO的txt 3、配置YOLO11代码工程 4、数据集yaml配置文件 5、YOLO11模型结构配置文件 6、编写训练代码 7、开始训…

基于neo4j旅游领域智能问答与图片展示系统

如果你正在苦恼选什么项目做毕业设计&#xff0c;或者对旅游、人工智能、数据可视化感兴趣&#xff0c;那么千万别错过这款基于Neo4j的互联网智能问答与旅游图片展示系统&#xff01;&#x1f60e;它不仅实用&#xff0c;还拥有丰富的数据资源&#xff0c;技术亮点也是满满的。…

【数据结构】快速排序(三种实现方式)

目录 一、基本思想 二、动图演示&#xff08;hoare版&#xff09; 三、思路分析&#xff08;图文&#xff09; 四、代码实现&#xff08;hoare版&#xff09; 五、易错提醒 六、相遇场景分析 6.1 ❥ 相遇位置一定比key要小的原因 6.2 ❥ 右边为key&#xff0c;左边先走 …

简单的windows java -jar 无法启动jar包解决方法

简单的windows java -jar 无法启动jar包解决方法 1. 问题 我们项目是使用nacos作为注册中心以及配置中心&#xff0c;我们本地使用idea 进行服务配置以及启动发现没有问题&#xff0c;然后我们的服务经过maven install 打包后发布到LINUX服务启动也没有问题&#xff0c;但是我…

三种单例实现

1、不继承Mono的单例 实现 使用 注&#xff1a; 使用需要继承BaseManager 泛型填写自己本身 需要实现无参构造函数 2、挂载式的Mono单例 实现 使用 注&#xff1a; 使用需要继承SingletonMono 泛型填写自己本身 需要挂载在unity引擎面板 3、不用挂载式的单例 实现 使…