一、快速幂
在golang 学习4.快速幂与乘法逆元模板-CSDN博客中涉及到,这次重温一下。以下为代码,原理不再赘述。
private long quickPow(int x, long n) {
long res = 1;
long t = x;
while (n != 0) {
if ((n & 1) == 1) {
res *= t;
res %= 1000000007;
}
t *= t;
t %= 1000000007;
n /= 2;
}
return res;
}
博主在做LCR 132. 砍竹子 II - 力扣(LeetCode)时,发现数据量较小时,可以使用动态规划来做如343. 整数拆分 - 力扣(LeetCode),时间复杂度空间复杂度皆为O(n)。但数据量较大时,只能贪心+快速幂来解决。
本题中,要想使一个数拆分后乘积最大,因子只能是3。当n小于等于3,拆分成两个数,乘积最大为n-1;大于3时,要想尽办法,使得因子中有更多的3,即8拆分成3*3*2,10拆分成3*3*4。总结规律发现,n%3==0,result=quickPow(3,n/3);n%3==1,此时会剩下一个1,这样1就浪费了,可以转化成3*1 -> 2*2,因此result=quickPow(3,n/3-1)*4;n%3==2,result=quickPow(3,n/3)*2。
综上,整理代码如下,这里p作为参数传递:
class Solution {
public int cuttingBamboo(int bamboo_len) {
if(bamboo_len <= 3) return bamboo_len - 1;
int b = bamboo_len % 3, p = 1000000007;
long rem = quickPow(3,bamboo_len/3-1,p);
if(b == 0) return (int)(rem * 3 % p);
if(b == 1) return (int)(rem * 4 % p);
return (int)(rem * 6 % p);
}
private long quickPow(int x, long n, int p) {
long res = 1;
long t = x;
while (n != 0) {
if ((n & 1) == 1) {
res *= t;
res %= p;
}
t *= t;
t %= p;
n /= 2;
}
return res;
}
}
二、乘法逆元
首先要知道什么是乘法逆元:,x是a mod b的乘法逆元,类似于“倒数”。
在我们求解x/a对b取模的结果时,x可能是个很大的数,只能先x mod b=e,再利用中间结果e除以a。一旦e无法整除a,结果可能就有问题。因此需要先求乘法逆元,将“除法”变成“乘法”。
根据费马小定理可以求出,乘法逆元,此时quickPow(a,b-1,b)便可以通过快速幂计算。
一般题目比较少,不过阿里喜欢考察数学原理,不可不提防。