快速幂和大数求余解法
50. Pow(x, n)
思路
不用递归
设 res=1,则初始状态 x^n = x^n × res 。
在循环二分时,每当 n 为奇数时,将多出的一项 x 乘入 res ,则最终可化至 x^n = x^0 × res = res ,返回 res。
代码
class Solution {
public double myPow(double x, int n) {
long N = n;
return N >= 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N);
}
public double quickMul(double x, long N) {
if (N == 0) {
return 1.0;
}
double y = quickMul(x, N / 2);
return N % 2 == 0 ? y * y : y * y * x;
}
}
不用递归
class Solution {
public double myPow(double x, int n) {
if(x == 0.0f) return 0.0d;
long b = n;
double res = 1.0;
if(b < 0) {
x = 1 / x;
b = -b;
}
while(b > 0) {
if((b & 1) == 1) res *= x;
x *= x;
b >>= 1;
}
return res;
}
}
剑指 Offer 14- II. 剪绳子 II
思路
数学推导:
推论一: 将绳子以相等的长度等分为多段 ,得到的乘积最大。
推论二: 尽可能将绳子以长度 3 等分为多段时,乘积最大。
切分规则:
- 最优: 3 ;
把绳子尽可能切为多个长度为 3 的片段,留下的最后一段绳子的长度可能为 0,1,2 三种情况。 - 次优: 2 ;
若最后一段绳子长度为 2 ;则保留 。 - 最差: 1 。
若最后一段绳子长度为 1 ;则应把一份 3+1 替换为 2+2,因为 2×2 > 3×1。
大数求余解法
大数求余问题: 在仅使用 int32 类型存储的前提下,正确计算 x^a 对 p 求余(即 x^a ⊙ p )的值。
解决方案: 循环求余 、 快速幂求余 ,其中后者的时间复杂度更低,两种方法均基于以下求余运算规则推出:
(xy) ⊙ p=[(x ⊙ p)(y ⊙ p)] ⊙ p
快速幂求余
# 求 (x^a) % p —— 快速幂求余
def remainder(x, a, p):
rem = 1
while a > 0:
if a % 2: rem = (rem * x) % p
x = x ** 2 % p
a //= 2
return rem
代码
class Solution {
public int cuttingRope(int n) {
if(n <= 3) return n - 1;
int b = n % 3, p = 1000000007;
long rem = 1, x = 3;
for(int a = n / 3 - 1; a > 0; a /= 2) {
if(a % 2 == 1) rem = (rem * x) % p;
x = (x * x) % p;
}
if(b == 0) return (int)(rem * 3 % p);
if(b == 1) return (int)(rem * 4 % p);
return (int)(rem * 6 % p);
}
}