快速幂算法详解(C++实现)

文章目录

  • 1. 什么是快速幂
  • 2. 暴力求解
    • 代码实现
    • 缺陷分析
  • 3. 优化一:取模运算的性质
  • 4. 优化二:快速幂算法的核心思想
  • 5. 终极优化:位运算优化
  • 6. 源码

这篇文章我们来一起学习一个算法——快速幂算法。

1. 什么是快速幂

顾名思义,快速幂就是快速算底数的n次幂。其时间复杂度为 O(log₂N), 与朴素的O(N)相比效率有了极大的提高。

那快速幂算法呢一般就是用来解决如下的问题:

在这里插入图片描述
我们看到它的取值范围是比较大的,所以我们可以用long long

2. 暴力求解

代码实现

那这个问题呢乍一看很简单:

我们可以考虑用循环(或者使用pow函数)直接计算a^b的值,然后对c去模即可。
在这里插入图片描述

缺陷分析

但是呢,这样写我们的算法其实是有去缺陷的:

首先它的时间复杂度是O(b),而上面题目中b的取值是【0,10^18】。
所以当b的取值比较大的时候,时间复杂度就会很大,那么算法的效率就比较低。
此外这里的ret不断乘等以a,它的范围是很有可能超过long long 的。
在这里插入图片描述
那一旦溢出的话,结果可能就错了。

所以我们要想办法对该算法进行优化

3. 优化一:取模运算的性质

首先我们可以根据取模运算的性质进行第一重优化:

取模运算是满足这样一条性质的
(a*b)%c=((a%c)*(b%c))%c
大家有兴趣可以自己证明一下
那这样的话我们之前是每次让ret*=a,乘等b次,最后再去模。
那现在我们可以在每次ret*=a之后都对ret进行一次取模
在这里插入图片描述
那这样的话ret就不太容易溢出了。

long long fastPow(long long a, long long b, long long c)
{long long ret = 1;for (int i = 0; i < b; i++){ret *= a;ret %= c;}return ret % c;
}

但是,是否仍然有缺陷呢?

🆗,它的时间复杂度并没有得到优化,还是O(b)

所以,我们再来想办法优化:

4. 优化二:快速幂算法的核心思想

快速幂算法的核心思想就是每一步都把指数分成两半,而相应的底数做平方运算。这样不仅能把非常大的指数给不断变小,所需要执行的循环次数也变小,而最后表示的结果却一直不会变。

我们来举个例子:

比如算3^10
那其实可以这样写:
3^10=(3^2)^5=9^5=9*9^4=9*81^2
那观察这个式子其实我们能发现这样的规律:

  1. 如果指数是是偶数的话,那么指数除以2,底数平方,前后的值是相等的。(ret*3^10=ret*(3^2)^5
  2. 如果指数是奇数的话,先将ret*=底数,然后依然是指数除以2,底数平方,前后值相同(ret*9^5=ret*9*81^2

那我们来算一下这种写法的时间复杂度:

这样优化之后呢,每次指数的值都会/=2,即b/=2,那之前我们要循环b次,现在就是O(logb),即以2为底,b的对数。

那我们来写一下代码:

在这里插入图片描述
那此外,为了防止输入的a过大的话,我们上来可以直接对a取模
在这里插入图片描述

5. 终极优化:位运算优化

那针对上面的代码,有两处地方我们其实还可以进行一个优化:

首先
在这里插入图片描述
判断指数是偶数还是奇数这里,还有一种更高效的方法就是使用位运算,让b&1,因为1的补码只有最后一位为1,其余全为0,如果b是奇数的话,那它的最后一位为1,b&1的结果就是1,如果b是偶数,那最后一位为0,b&1的结果是0
在这里插入图片描述
然后就是:
在这里插入图片描述
b/=2这里,我们可以用b>>=1代替(整数算术右移一位相当于除以2并向下取整)
在这里插入图片描述
关于移位操作符如果大家遗忘了可以看: 【C操作符详解】之 移位操作符

我找了一道OJ,我们可以来测试一下:

在这里插入图片描述
在这里插入图片描述

没有问题!

6. 源码

#include <iostream>
using namespace std;
long long fastPow(long long a, long long b, long long c)
{long long ret = 1;a %= c;while (b){if (b & 1){ret *= a;ret %= c;}a *= a;a %= c;b >>= 1;}return ret;
}int main()
{long long a = 0;long long b = 0;long long m = 0;cin >> a >> b >> m;cout << fastPow(a, b, m) << endl;return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leetCode 1080.根到叶路径上的不足节点 + 递归

给你二叉树的根节点 root 和一个整数 limit &#xff0c;请你同时删除树中所有 不足节点 &#xff0c;并返回最终二叉树的根节点。假如通过节点 node 的每种可能的 “根-叶” 路径上值的总和全都小于给定的 limit&#xff0c;则该节点被称之为 不足节点 &#xff0c;需要被删除…

Gson详解(一)

一.Gson说明 Gson&#xff08;又称Google Gson&#xff09;是Google公司发布的一个开放源代码的Java库&#xff0c;主要用途为序列化Java对象为JSON字符串&#xff0c;或反序列化JSON字符串成Java对象。而JSON(JavaScriptObject Notation) 是一种轻量级的数据交换格式&#xf…

第十五章 解读argparse模块用法实例(工具)

argsparse是python的命令行解析的标准模块&#xff0c;内置于python&#xff0c;不需要安装。这个库可以让我们直接在命令行中就可以向程序中传入参数并让程序运行。 港真的&#xff0c;今天是我第一次学习argsparse。因为用不到&#xff0c;自然也就没有学习的动力。但是现在…

C语言-内存函数详解

文章目录 1. memcpy使用和模拟实现2. memmove使用和模拟实现3. memset函数的使用4. memcmp函数的使用 1. memcpy使用和模拟实现 返回类型和参数&#xff1a; void * memcpy ( void * destination, const void * source, size_t num );1.函数memcpy从source的位置开始向后复制…

R语言实现Lasso回归

一、Lasso回归 Lasso 回归&#xff08;Least Absolute Shrinkage and Selection Operator Regression&#xff09;是一种用于线性回归和特征选择的统计方法。它在回归问题中加入了L1正则化项&#xff0c;有助于解决多重共线性&#xff08;多个特征高度相关&#xff09;和特征选…

设备树是什么?

设备树&#xff1a; 设备树DTS(Device Tree Source) 描述设备信息的独立的文件。 为什么要引入设备树&#xff1f; 随着芯片的发展&#xff0c;Linux内核中就包含着越来越多这些描述设备的代码&#xff0c;导致Linux内核代码会很臃肿。因此引入了设备树文件&#xff0c;从…

基于 GPS 定位信息的 Pure-Pursuit 轨迹跟踪实车测试(1)

基于 GPS 定位信息的 Pure-Pursuit 轨迹跟踪实车测试&#xff08;1&#xff09; 进行了多组实验&#xff0c;包括顺逆时针转向&#xff0c;直线圆弧轨迹行驶&#xff0c;以及Pure-Pursuit 轨迹跟踪测试 代码修改 需要修改的代码并不多&#xff0c;主要对 gps_sensor 功能包和…

Java中的泛型是什么?如何使用泛型类和泛型方法?

Java 中的泛型是一种编程机制&#xff0c;允许你编写可以与多种数据类型一起工作的代码&#xff0c;同时提供编译时类型检查以确保类型的安全性。泛型的主要目的是提高代码的可重用性、类型安全性和程序的整体性能。 泛型类&#xff08;Generic Class&#xff09;: 在泛型类中…

【教3妹学编程-算法题】统计子串中的唯一字符

3妹&#xff1a;“太阳当空照&#xff0c;花儿对我笑&#xff0c;小鸟说早早早&#xff0c;你为什么背上炸药包” 2哥 :3妹&#xff0c;什么事呀这么开发。 3妹&#xff1a;2哥你看今天的天气多好啊&#xff0c;阳光明媚、万里无云、秋高气爽&#xff0c;适合秋游。 2哥&#x…

关于python中的nonlocal关键字

如果在函数的子函数中需要调用外部变量&#xff0c;一般会看见一个nonlocal声明&#xff0c;类似下面这种&#xff1a; def outer_function():x 10def inner_function():nonlocal xx 1print(x)inner_function()outer_function()在这个例子中&#xff0c;inner_function 引用…

【DevOps】基于 KubeSphere 的 Kubernetes 生产实践之旅(万字长文)

基于 KubeSphere 的 Kubernetes 生产实践 1.KubeSphere 简介1.1 全栈的 Kubernetes 容器云 PaaS 解决方案1.2 选型理由&#xff08;从运维的角度考虑&#xff09; 2.部署架构图3.节点规划3.1 软件版本3.2 规划说明3.2.1 K8s 集群规划3.2.2 存储集群3.2.3 中间件集群3.2.4 网络规…

SpringBoot——LiteFlow引擎框架

优质博文&#xff1a;IT-BLOG-CN 一、LiteFlow 简介 LiteFlow是一个轻量且强大的国产规则引擎框架&#xff0c;可用于复杂的组件化业务的编排领域。帮助系统变得更加丝滑且灵活。利用LiteFlow&#xff0c;你可以将瀑布流式的代码&#xff0c;转变成以组件为核心概念的代码结构…

计算机组成原理-Cache的基本概念和原理

文章目录 存储系统存在的问题Cache的工作原理局部性原理性能分析例题界定何为局部部分问题总结 存储系统存在的问题 增加Cache层来缓和CPU和主存的工作速度矛盾 Cache的工作原理 启动某个程序后&#xff0c;将程序的代码从辅存中取出放入内存中&#xff0c;再从内存中将代码…

【安全】2.6.6版本的audit审计机制分析

文章目录 2.6.6版本的audit审计机制分析1 关于内核版本2 入口3 audit初始化4 系统调用审计流程5 配置下发流程6 总结 2.6.6版本的audit审计机制分析 1 关于内核版本 linux内核从2.6.6版本开始支持audit机制&#xff0c;为了更好的理解audit本身的机制&#xff0c;需要对audit…

机器人开发的选择

喷涂机器人 码垛机器人 纸箱码垛机器人 焊接机器人 跳舞机器人 管道清理机器人 工地巡检机器人 点餐机器人 化工巡检机器人 装箱机器人 安防巡检机器人 迎宾机器人好像有点像软银那个 污水管道检测机器人 大酒店用扫地机器人 家用扫地机器人 工厂用&#xff08;…

知识图谱06——将pdf中的表格(文字形式)保存至csv中

使用ubuntu22.04&#xff0c;anaconda 由于装环境装了一阵子&#xff0c;不确定装了哪些包了 可能的环境安装 conda install -c conda-forge pymupdf conda install -c conda-forge camelot-py conda install pandas #或者 pip install PyMuPDF pip install camelot-py[all] …

求链表环的起始位置

leetcode中题目位置 https://leetcode.cn/problems/linked-list-cycle-ii/submissions/?envTypestudy-plan-v2&envIdtop-100-liked 代码&#xff1a; public class Solution {public ListNode detectCycle(ListNode head) {if (head null || head.next null) {return…

S25FL系列FLASH读写的FPGA实现

文章目录 实现思路具体实现子模块实现top模块 测试Something 实现思路 建议读者先对 S25FL-S 系列 FLASH 进行了解&#xff0c;我之前的博文中有详细介绍。 笔者的芯片具体型号为 S25FL256SAGNFI00&#xff0c;存储容量 256Mb&#xff0c;增强高性能 EHPLC&#xff0c;4KB 与 6…

Could not resolve all files for configuration ‘:app:androidJdkImage‘.

在使用./gradlew build编译项目时候遇到了该问题&#xff0c;整体错误如下: * What went wrong: Configuration cache state could not be cached: field generatedModuleFile of com.android.build.gradle.tasks.JdkImageInput bean found in field compilerArgumentProvider…

Leetcode199. 二叉树的右视图

Every day a Leetcode 题目来源&#xff1a;199. 二叉树的右视图 解法1&#xff1a;层序遍历 给定一个二叉树的 根节点 root&#xff0c;想象自己站在它的右侧&#xff0c;按照从顶部到底部的顺序&#xff0c;返回从右侧所能看到的节点值。 按层序遍历&#xff0c;将每层的…