快速幂实现pow函数(从二分和二进制两种角度理解快速幂)
文章目录
- 迭代实现快速幂
- 思路
- int的取值范围
- 快速幂
- 从二进制的角度来理解
- 从二分法的角度来理解
- 代码
- 复杂度分析
- 进阶——超级次方
- 思路
- 倒序+快速幂
- 正序+快速幂
- 代码
- 复杂度分析
迭代实现快速幂
实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。不得使用库函数,同时不需要考虑大数问题。
示例 1:
输入:x = 2.00000, n = 10
输出:1024.00000
示例 2:
输入:x = 2.10000, n = 3
输出:9.26100
示例 3:
输入:x = 2.00000, n = -2
输出:0.25000
解释:2-2 = 1/22 = 1/4 = 0.25
提示:
-100.0 < x < 100.0
-231 <= n <= 231-1
-104 <= xn <= 104
思路
想用累乘处理幂路子就走窄了,超时是板上钉钉的。
用快速幂的思想才符合题目考察的意图,在详说快速幂之前说一个很刁钻的测试用例 —— n=-2147483648
。
int的取值范围
我们知道:
- int的取值范围是
-2147483648
(-231)到2147483647
(231 - 1) -2147483648
有一位符号位可用,因此2147483647
是32位操作系统中最大的符号型整型常量。- 当出现这个刁钻的测试用例时,如果对n粗暴的取绝对值的话,int是容纳不下的,因此当
n<0
时, 需要定义一个long long
类型变量m
来存储n
的绝对值。
快速幂
从二进制的角度来理解
- 对于任何十进制正整数 n ,设其二进制为
则有:
- 根据以上推导,可把计算 xn 转化为解决以下两个问题:
- 因此,应用以上操作,可在循环中依次计算
的值,并将所有累计相乘即可。
从二分法的角度来理解
快速幂实际上是二分思想的一种应用。
- 二分推导: xn = xn/2 × xn/2 = (x2)n/2,令
n/2
为整数,则需要分为奇偶两种情况(设向下取整除法符号为 “//” ):
- 幂获取结果:
- 根据二分推导,可通过循环 x = x2 操作,每次把幂从
n
降至n//2
,直至将幂降为0
; - 设
sum=1
,则初始状态 xn = xn × sum。在循环二分时,每当n
为奇数时,将多出的一项x
乘入sum
,则最终可化至 xn = x0 * sum = sum,返回sum
即可。
转自作者:jyd
算法流程:
- 当
x = 0
时:直接返回 0 (避免后续x = 1 / x
操作报错)。 - 初始化
sum = 1
; - 当
n < 0
时:把问题转化至n≥0
的范围内,即执行x = 1/x
,n = - n
; - 循环计算:当
n = 0
时跳出;
- 当
n&1=1
时:将当前x
乘入sum
(即sum∗=x
); - 执行 x = x2(即
x∗=x
); - 执行
n
右移一位(即n>>=1
)。
- 返回 sum。
代码
class Solution {public:double myPow(double x, int n) {if(x == 0) return 0;double sum = 1;long long m = n;if(n < 0){x = 1.0/x;m = -m;}while(m > 0){if(m & 1){sum *= x;}x *= x;m >>= 1;}return sum;}
};
复杂度分析
- 时间复杂度 O(log_2 n): 二分的时间复杂度为对数级别。
- 空间复杂度 O(1): sum, b 等变量占用常数大小额外空间。
进阶——超级次方
计算 ab 对 1337
取模,a 是一个正整数,b 是一个非常大的正整数且会以数组形式给出。
思路
本题的难点在于对 数组b
的处理,显然无法将其转为 一个具体类型,因此解决方法无非就是 在 倒序 or 正序 遍历数组的同时进行次方处理。
倒序+快速幂
本质无非就是把上面提到的二进制思想转为十进制,具体来说:
223 可以看作 2(10 * 2) + (1 * 3) ,也就是 10242 * 23 。
那么我们只需要在第 k
次 倒序遍历 数组 b
的同时,记录 a
的 10k-1 次方即可。
正序+快速幂
思路源于秦九韶算法,一般地,一元 n
次多项式的求值需要经过 (n+1)∗n2\frac{(n+1)*n}{2}2(n+1)∗n 次乘法和 nnn 次加法,而秦九韶算法只需要 nnn 次乘法和 nnn 次加法。大大简化了运算过程。
把一个 n 次多项式:
改写成如下形式:
举个具体的例子,计算 22342^{234}2234:
2234=2200+30+4=2200∗230∗24=(220∗23)10∗24=[(110∗22)10∗23]10∗242^{234} = 2^{200+30+4} = 2^{200} * 2^{30} * 2^4 = (2^{20} * 2^3)^{10} * 2^4 = [(1^{10} * 2^2)^{10} * 2^3]^{10} * 2^42234=2200+30+4=2200∗230∗24=(220∗23)10∗24=[(110∗22)10∗23]10∗24
最后一步推导实际上是对规律的归纳,即:以 1
作为初始值 res
,每次有 新项 加入时,对 res
执行 res=res10∗新项res = res^{10} * 新项res=res10∗新项 的操作。
代码
class Solution {const int MOD = 1337;int quickmul(int x, int n){ // 快速幂实现pow功能if(x == 0) return 0;int sum = 1;while(n){if(n&1) sum = (long)sum * x % MOD;n >>= 1;x = (long)x * x % MOD;}return sum;}
public:int superPow(int a, vector<int>& b) { // 倒序int res = 1, n = b.size();for(int i=n-1; i>=0; i--){res = (long)res * quickmul(a, b[i]) % MOD;a = quickmul(a, 10); // 记录当前 a 的幂}return res;}int superPow(int a, vector<int>& b) { // 正序int res = 1, n = b.size();for(int i : b){res = (long)quickmul(res, 10) * quickmul(a, i) % MOD;// 加入新项时,对 res 执行 res = res^10 * 新项 的操作}return res;}
};
复杂度分析
- 时间复杂度O(∑i=0n−1logbi\sum_{i=0}^{n-1}{\log{b_i}}∑i=0n−1logbi): 其中
n
是数组b
的长度,对每个 bib_ibi 计算快速幂的时间为 O(logbi\log{b_i}logbi)。 - 空间复杂度O(1): 过程由迭代实现,避免了递归方法对栈空间的占用,只需要常数的空间存放若干变量。
快速幂实现pow函数(从二分和二进制两种角度理解快速幂)相关推荐
- java语言不用pow函数求x的n次方_【算法】自己实现x的n次幂(pow函数)
面试遇到了一个问题,是自己实现一个pow(x,n)函数返回一个值,是x的n次幂,回想当时回答的不好,就是死板的直接while 一直乘下去,面试官始不太满意,我想也是,这也太简单了,可是当时死活也想不出 ...
- python列表去重函数_对python中两种列表元素去重函数性能的比较方法
测试函数: 第一种:list的set函数 第二种:{}.fromkeys().keys() 测试代码: #!/usr/bin/python #-*- coding:utf-8 -*- import t ...
- 归一化mysql函数_数据归一化和两种常用的归一化方法
数据归一化和两种常用的归一化方法 一.总结 一句话总结: min-max标准化:x* =(x-min)/(max-min):新数据加入,需重新计算max和min Z-score标准化:x* =(x-μ ...
- OFD文件怎么转换成图片?这两种方法能够快速转换
怎么将OFD文件转换成图片呢?OFD文件是我们国家自主研发的一种文件版式格式标准,大家对于这种受用面较小的文件格式见到的次数可能不多,因此也对这种格式的文件不太了解,打开它需要相关的OFD阅读软件才可 ...
- C语言getline函数CSDN,c++中的两种getline用法详解
getline是C++标准库函数:但不是C标准库函数,而是POSIX(IEEE Std 1003.1-2008版本及以上)所定义的标准库函数(在POSIX IEEE Std 1003.1-2008标准 ...
- 二级指针在子函数中申请内存的两种方式
二级指针:在主函数中申明变量,在子函数中分配内存,有两种方式返回二级指针.在这个过程只有深刻理解了C的函数调用模型,以及指针的内存模型,才能够掌握好. #pragma once #include &l ...
- qt槽函数如何传递多个参数_Qt中connect函数不能传递参数的两种解决方法
Qt中的connect函数可以让我们动态地管理信号和槽. 比如现在界面上有一个标签,id为label.我现在想要动态地创建一个按键,id为push,然后利用connect函数,实现点击push以后,l ...
- 插入排序-一函数实现升降序的两种方式
方式一:传整数参数判断升降排序 void insertion_sort(int *sort_arr, int start, int end, char sort_choice){int i = 0, ...
- mstsc远程连接发生身份验证错误要求的函数不受支持的两种解决方法
mstsc远程连接发生身份验证错误要求的函数不受支持解决方法 1:可以找到加密oracle修正 按下 windows + R,调出运行窗口,输入 gpedit.msc ,回车即可 打开"本地 ...
最新文章
- Linux服务器部署ssl证书教程,linux服务器在wdcp面板安装ssl证书教程
- DFS(二):骑士游历问题
- css实现圆形钟表,js+css3圆形指针时钟代码
- 用java编写打印时间_编写一个java程序,读取系统时间,然后将时间用中文输出...
- 京东扳回一城,拼多多该小心了?
- 常见视频接口介绍,VGA,YPbPr,DVI,HDMI,DisplayPort
- IOS高级编程之二:IOS的数据存储与IO
- 月均数据_程序员月均薪多少,2019全国互联网行业程序员就业大数据报告
- 5G赋能中国智慧教育
- CVPR 2021 目标检测、跟踪和姿态估计最新进展分享
- CoAP学习笔记——服务器端繁忙时的处理请求流程
- QTcpServer和QTcpSocket使用详解
- wheeltech惯导模块使用
- Chrome不保留历史记录,常规模式下不保留历史记录
- 手机上定时日程提醒怎么设置?
- APP运行时Crash自动修复系统
- android10全面屏手势 操作图,丨系统设计丨ZUI 10加入更多全面屏手势
- 条件求和:SUMIF、SUMIFS函数
- 用java开发编译器之:Thompson构造,将正则表达式转换为有限状态自动机
- Hbase+Solr操作手册
热门文章
- linux 安全审计功能,数据库安全审计在数据安全中的功能
- 关闭SQLite3中的journal暂存档
- 客户机和服务器在s7通信中各有什么作用,哪些通信口可以进行 Modbus TCP 通讯,作为 Modbus 服务器的 SIMATIC S7 CPU 可以...
- 神经网络与深度学习——TensorFlow2.0实战(笔记)(四)(python函数)
- 【转】Dynamics 365中的事件框架与事件执行管道(Event execution pipeline)
- 【转】带你玩转Visual Studio——03.带你了解VC++各种类型的工程
- “菜”鸟理解.NET Framework(CLI,CLS,CTS,CLR,FCL,BCL)
- 【转】3.2SharePoint服务器端对象模型 之 访问文件和文件夹(Part 2)
- 【转】JPA、Hibernate和Mybatis区别和总结
- mysql系列:加深对脏读、脏写、可重复读、幻读的理解