标签:q1 q2 比赛 int res 必备 long 快速 复杂度
快速幂
快速幂一般用来解决 ab % c 的问题,当然计算不模c的情况也行。
1.暴力
// 返回结果a^b % c (c的范围一般很小所以用了int) public long pow(long a, long b, int c) { long res = 1; for (long i = 0 ; i < b; i++) { res *= a; } return res % c; }
这种方法对于数据范围小的情况还是可以的,但在特殊的情况下b的范围很大,例如 0 < b < 1018
缺陷:
-
计算中的res很容易超过long
-
时间复杂度高 O(N)
2.解决溢出问题
取模运算有个性质:(a * b) % p = ((a % p) * (b % p)) % p
下面我们来简单证明下:
设:a = k1 * p + q1 b = k2 * p + q2
(a * b) = (...) * p + q1 * q2
即 (a * b) % p = (q1 * q2) % p (这里不知道q1 * q2是否大于p,所以还要取模一下)
又因为 a % p = (k1 * p + q1) % p = q1 b % p = (k2 * p + q2) % p = q2
所以 (a * b) % p = ((a % p) * (b % p)) % p
但这有什么用呢?
我们之前是( a * a * ...) % c,根据这个性质我们就可以边乘边对c取摸了,这样不就解决了溢出问题了吗
即:ans *= a; ans %= c;
但还有缺陷:
-
时间复杂度的问题没有解决
3.降低时间复杂度
先看一下我们手算310是怎么算的?
310 = (32)5 = 95 = 9 * 94 = 9 * (92)2 = 9 * 812 ....
根据上面,我们很容易发现规律:
当指数是偶数时,让指数除2,底数平方。 当指数是奇数的时候让res乘一个底数,在让指数除2,底数平方
这个算法是时间复杂度是多少? 每次让指数 b /= 2,显然是O(logN)
4.代码实现
1.详细版
public long quickPow(long a, long b, int c) { a %= c; // 防止一开始a过大 long res = 1; // 其实这里用int也行 while(b > 0) { if (b % 2 == 1) // 指数是奇数 { res = (res * a) % c; // 边乘边摸 a = (a * a) % c; b /= 2; } else // 指数是偶数 { a = (a * a) % c; b /= 2; } } return res; }
2.简洁版+位运算优化
public long quickPow(long a, long b, int c) { a %= c; long res = 1; while(b > 0) { if (b & 1 == 1) // b % 2 == 1 { res = (res * a) % c; } a = (a * a) % c; b >>= 1; // b /= 2; } return res; }
5.课后习题
leetcode :
标签:q1,q2,比赛,int,res,必备,long,快速,复杂度 来源: https://blog.csdn.net/m0_53492310/article/details/121763700
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。