文章目录

  • 迭代实现快速幂
    • 思路
      • 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)到2147483647231 - 1
  • -2147483648有一位符号位可用,因此2147483647是32位操作系统中最大的符号型整型常量。
  • 当出现这个刁钻的测试用例时,如果对n粗暴的取绝对值的话,int是容纳不下的,因此当 n<0 时, 需要定义一个long long类型变量 m 来存储 n 的绝对值。

快速幂

从二进制的角度来理解

  • 对于任何十进制正整数 n ,设其二进制为
    则有:

  • 根据以上推导,可把计算 xn 转化为解决以下两个问题:

  • 因此,应用以上操作,可在循环中依次计算
    的值,并将所有累计相乘即可。



从二分法的角度来理解

快速幂实际上是二分思想的一种应用。

  • 二分推导: xn = xn/2 × xn/2 = (x2)n/2,令 n/2 为整数,则需要分为奇偶两种情况(设向下取整除法符号为 “//” ):

  • 幂获取结果:
  1. 根据二分推导,可通过循环 x = x2 操作,每次把幂从 n 降至 n//2 ,直至将幂降为 0
  2. sum=1 ,则初始状态 xn = xn × sum。在循环二分时,每当 n 为奇数时,将多出的一项 x 乘入 sum ,则最终可化至 xn = x0 * sum = sum,返回 sum 即可。

转自作者:jyd

算法流程:

  1. x = 0 时:直接返回 0 (避免后续 x = 1 / x 操作报错)。
  2. 初始化 sum = 1
  3. n < 0 时:把问题转化至 n≥0 的范围内,即执行 x = 1/xn = - n
  4. 循环计算:当 n = 0 时跳出;
  • n&1=1 时:将当前 x 乘入 sum(即 sum∗=x );
  • 执行 x = x2(即 x∗=x );
  • 执行 n 右移一位(即 n>>=1)。
  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 等变量占用常数大小额外空间。

进阶——超级次方

计算 ab1337 取模,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−1log⁡bi\sum_{i=0}^{n-1}{\log{b_i}}∑i=0n−1​logbi​): 其中 n 是数组 b 的长度,对每个 bib_ibi​ 计算快速幂的时间为 O(log⁡bi\log{b_i}logbi​)。
  • 空间复杂度O(1): 过程由迭代实现,避免了递归方法对栈空间的占用,只需要常数的空间存放若干变量。

快速幂实现pow函数(从二分和二进制两种角度理解快速幂)相关推荐

  1. java语言不用pow函数求x的n次方_【算法】自己实现x的n次幂(pow函数)

    面试遇到了一个问题,是自己实现一个pow(x,n)函数返回一个值,是x的n次幂,回想当时回答的不好,就是死板的直接while 一直乘下去,面试官始不太满意,我想也是,这也太简单了,可是当时死活也想不出 ...

  2. python列表去重函数_对python中两种列表元素去重函数性能的比较方法

    测试函数: 第一种:list的set函数 第二种:{}.fromkeys().keys() 测试代码: #!/usr/bin/python #-*- coding:utf-8 -*- import t ...

  3. 归一化mysql函数_数据归一化和两种常用的归一化方法

    数据归一化和两种常用的归一化方法 一.总结 一句话总结: min-max标准化:x* =(x-min)/(max-min):新数据加入,需重新计算max和min Z-score标准化:x* =(x-μ ...

  4. OFD文件怎么转换成图片?这两种方法能够快速转换

    怎么将OFD文件转换成图片呢?OFD文件是我们国家自主研发的一种文件版式格式标准,大家对于这种受用面较小的文件格式见到的次数可能不多,因此也对这种格式的文件不太了解,打开它需要相关的OFD阅读软件才可 ...

  5. C语言getline函数CSDN,c++中的两种getline用法详解

    getline是C++标准库函数:但不是C标准库函数,而是POSIX(IEEE Std 1003.1-2008版本及以上)所定义的标准库函数(在POSIX IEEE Std 1003.1-2008标准 ...

  6. 二级指针在子函数中申请内存的两种方式

    二级指针:在主函数中申明变量,在子函数中分配内存,有两种方式返回二级指针.在这个过程只有深刻理解了C的函数调用模型,以及指针的内存模型,才能够掌握好. #pragma once #include &l ...

  7. qt槽函数如何传递多个参数_Qt中connect函数不能传递参数的两种解决方法

    Qt中的connect函数可以让我们动态地管理信号和槽. 比如现在界面上有一个标签,id为label.我现在想要动态地创建一个按键,id为push,然后利用connect函数,实现点击push以后,l ...

  8. 插入排序-一函数实现升降序的两种方式

    方式一:传整数参数判断升降排序 void insertion_sort(int *sort_arr, int start, int end, char sort_choice){int i = 0, ...

  9. mstsc远程连接发生身份验证错误要求的函数不受支持的两种解决方法

    mstsc远程连接发生身份验证错误要求的函数不受支持解决方法 1:可以找到加密oracle修正 按下 windows + R,调出运行窗口,输入 gpedit.msc ,回车即可 打开"本地 ...

最新文章

  1. Linux服务器部署ssl证书教程,linux服务器在wdcp面板安装ssl证书教程
  2. DFS(二):骑士游历问题
  3. css实现圆形钟表,js+css3圆形指针时钟代码
  4. 用java编写打印时间_编写一个java程序,读取系统时间,然后将时间用中文输出...
  5. 京东扳回一城,拼多多该小心了?
  6. 常见视频接口介绍,VGA,YPbPr,DVI,HDMI,DisplayPort
  7. IOS高级编程之二:IOS的数据存储与IO
  8. 月均数据_程序员月均薪多少,2019全国互联网行业程序员就业大数据报告
  9. 5G赋能中国智慧教育
  10. CVPR 2021 目标检测、跟踪和姿态估计最新进展分享
  11. CoAP学习笔记——服务器端繁忙时的处理请求流程
  12. QTcpServer和QTcpSocket使用详解
  13. wheeltech惯导模块使用
  14. Chrome不保留历史记录,常规模式下不保留历史记录
  15. 手机上定时日程提醒怎么设置?
  16. APP运行时Crash自动修复系统
  17. android10全面屏手势 操作图,丨系统设计丨ZUI 10加入更多全面屏手势
  18. 条件求和:SUMIF、SUMIFS函数
  19. 用java开发编译器之:Thompson构造,将正则表达式转换为有限状态自动机
  20. Hbase+Solr操作手册

热门文章

  1. linux 安全审计功能,数据库安全审计在数据安全中的功能
  2. 关闭SQLite3中的journal暂存档
  3. 客户机和服务器在s7通信中各有什么作用,哪些通信口可以进行 Modbus TCP 通讯,作为 Modbus 服务器的 SIMATIC S7 CPU 可以...
  4. 神经网络与深度学习——TensorFlow2.0实战(笔记)(四)(python函数)
  5. 【转】Dynamics 365中的事件框架与事件执行管道(Event execution pipeline)
  6. 【转】带你玩转Visual Studio——03.带你了解VC++各种类型的工程
  7. “菜”鸟理解.NET Framework(CLI,CLS,CTS,CLR,FCL,BCL)
  8. 【转】3.2SharePoint服务器端对象模型 之 访问文件和文件夹(Part 2)
  9. 【转】JPA、Hibernate和Mybatis区别和总结
  10. mysql系列:加深对脏读、脏写、可重复读、幻读的理解