快速幂算法详解(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;
}

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

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

相关文章

将本地项目上传到gitee

本文详细介绍如何将本地项目上传到gitee 1.登录gitee创建一个与本地项目名相同的仓库 2.进入本地项目所在路径&#xff0c;打开Git Bash 3.执行初始化命令 git init4.添加远程仓库 4.1 点击复制你的HTTPS仓库路径 4.2 执行添加远程仓库命令 git remote add origin 你的…

【Vue】filter的用法

上一篇&#xff1a; vue的指令 https://blog.csdn.net/m0_67930426/article/details/134599378?spm1001.2014.3001.5502 本篇所使用指令 v-for v-on v-html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"&…

vivado产生报告阅读分析23-时序路径特性报告

时序路径特性报告 下图显示了在“ Timing Mode ” &#xff08; 时序模式 &#xff09; 下运行“ Report Design Analysis ” &#xff08; 设计分析报告 &#xff09; 的输出示例 &#xff0c; 其中显示了设计中 10 条最差建立路径的路径特性。在 Vivado IDE 中选中“ Repo…

【教学类-06-12】20231126 (一)二位数 如何让加减乘除题目从小到大排序(以1-20之间加法为例,做正序排列用)

结果展示 优化后 优化前 背景需求&#xff1a; 生成列表 单独抽取显示题目排序方法 存在问题: 我希望 00 01 02……这样排序&#xff0c;但是实际上&#xff0c;除了第一个加数会从小到大排序&#xff0c;第二个被加数的第十位数和个位数都会从小到大排序&#xff0c;也就是…

Blender学习--模型贴图傻瓜级教程

Blender 官方文档 1. Blender快捷键&#xff1a; 快捷键说明 按住鼠标滚轮&#xff1a;移动视角Tab&#xff1a;切换编辑模式和物体模式鼠标右键&#xff1a; 编辑模式&#xff1a; 物体模式&#xff1a; 其他&#xff1a; 2. 下面做一个球体贴一张纹理的操作 2.1 效果如下…

智能优化算法应用:基于粒子群算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于粒子群算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于粒子群算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.粒子群算法4.实验参数设定5.算法结果6.参考文献7.…

C++局域网从服务器获取已连接用户的列表(linux to linux)

目录 服务器端 代码 客户端 代码解析 服务器端 原理 遇到的阻碍以及解决办法 客户端 原理 遇到的阻碍以及解决办法 运行结果截图 总结 服务器端 代码 #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <netinet…

安捷伦E4404B频谱分析仪,100 Hz 至 6.7 GHz

E4404B是安捷伦ESA-E系列频谱分析仪&#xff0c;它是一款能够适应未来发展需求的中高端频谱分析仪解决方案。该系列在频谱分析仪的测量速度、动态范围、精度和功率分辨能力等方面&#xff0c;都为类似价位的产品树立了性能标杆。其灵活的平台设计使得研发、制造和现场服务工程师…

这一款 Mac 系统终端工具,已经用的爱不释手了!

&#x1f525;&#x1f525;&#x1f525;作为程序员或者运维管理人员&#xff0c;我们经常需要使用终端工具来进行服务器管理及各种操作&#xff0c;比如部署项目、调试代码、查看/优化服务、管理服务器等。 相信大家用的最多的终端工具就是 Xshell、iTerm2和Mobaxterm&#…

利用ngrok实现内网穿透(全网最详细教程)

准备工具&#xff1a; 1、phpstudy 用于在本地搭建网站 2、ngrok 用于将自己的本地端口暴露到公网上&#xff0c;从而实现内网穿透 文章开始前给大家分享一个学习人工智能的网站&#xff0c;通俗易懂&#xff0c;风趣幽默 人工智能https://www.captainbed.cn/myon/ ~~~~~…

ESP32和ESP8266的ESP-MESH

ESP32和ESP8266的ESP-MESH 功能介绍一、介绍ESP-MESH二、安装painlessMesh库三、ESP-MESH基本示例&#xff08;广播消息&#xff09;四、示范 功能介绍 了解如何使用ESP-MESH网络协议通过ESP32和ESP8266 NodeMCU板构建网状网络。 ESP-MESH允许多个设备&#xff08;节点&#x…

单例模式与多线程

目录 前言 正文 1.立即加载/饿汉模式 2.延迟加载/懒汉模式 1.延迟加载/懒汉模式解析 2.延迟加载/懒汉模式的缺点 3.延迟加载/懒汉模式的解决方案 &#xff08;1&#xff09;声明 synchronized 关键字 &#xff08;2&#xff09;尝试同步代码块 &#xff08;3&am…

vue 中 js 金额数字转中文

参考&#xff1a;js工具函数之数字转为中文数字和大写金额_js封装工具类函数金额大写-CSDN博客 我使用的框架vol.core。 客户需求要将录入框的金额数字转换成中文在旁边显示&#xff0c;换了几种函数&#xff0c;最终确定如下函数 function changeToChineseMoney(Num) {//判断…

Quartz定时任务基础

springBoot有一个定时执行某个方法的 注解&#xff1a; Scheduled 可以满足挺多的需求&#xff0c;但是到了一些场景&#xff0c;就显得比较麻烦&#xff0c;比如&#xff1a; 机器待机五分钟后执行切换待机状态。如果是按照使用Scheduled注解&#xff0c;就得持久化一个表&…

【Java SE】 带你走近Java的抽象类与接口

&#x1f339;&#x1f339;&#x1f339;【JavaSE】专栏&#x1f339;&#x1f339;&#x1f339; &#x1f339;&#x1f339;&#x1f339;个人主页&#x1f339;&#x1f339;&#x1f339; &#x1f339;&#x1f339;&#x1f339;上一篇文章&#x1f339;&#x1f339;&…

2018年3月26日 Go生态洞察:Go包版本管理提案分析

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

java springboot测试类虚拟MVC环境 匹配请求头指定key与预期值是否相同

上文 java springboot测试类虚拟MVC环境 匹配返回值与预期内容是否相同 (JSON数据格式) 版 中 我们展示 json匹配内容的方式 那么 本文我们来看看Content-Type属性的匹配方式 首先 我们从返回体可以看出 Content-Type 在请求头信息 Headers 中 我们直接将测试类代码更改如下 …

C#,《小白学程序》第二十七课:大数四则运算之“运算符重载”的算法及源程序

1 文本格式 using System; using System.Text; using System.Collections; using System.Collections.Generic; /// <summary> /// 大数的四则&#xff08;加减乘除&#xff09;运算 /// 及其运算符重载&#xff08;取余数&#xff09; /// </summary> public cl…

在项目中集成marsUI

拷贝文件夹到目标项目 集成 安装相关依赖 npm i --save ant-design-vue4.x npm i less npm i nprogress npm i consola npm i echarts npm i vue-color-kit npm i icon-park/svg npm i vite-plugin-style-import 配置Vite文件 使用 效果

Leetcode—828.统计子串中的唯一字符【困难】

2023每日刷题&#xff08;四十一&#xff09; Leetcode—828.统计子串中的唯一字符 算法思想 枚举所有种类字母在s中出现的位置&#xff0c;分别统计只包含这个字母不包含该类字母中其他字母的子串个数 实现代码 int uniqueLetterString(char* s) {int len strlen(s);cha…