给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m-1] 。请问 k[0]k[1]…*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
示例 1:
1 2 3
输入: 2 输出: 1 解释: 2 = 1 + 1, 1 × 1 = 1
示例 2:
1 2 3
输入: 10 输出: 36 解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
提示:
2 <= n <= 58
1. 贪心
如果我们给定了绳子长度n, 和绳子个数m, 那么就可以在O(1)时间内算出来最大乘积.
假设绳子可以取值实数, 最大解肯定是每个绳子的长度都一样长, 这样才能最大. 很简单的原理, 如果一个绳子长为a, 一个绳子长为b, (a != b), 那么换一种剪法, 都剪成(a + b) / 2的长度, 那么新的乘积((a + b) / 2) ^ 2肯定大于原来的乘积ab. (均值不等式)
privatedoublecuttingRope(int n, int m) { int len = n / m; int len_Plus1 = len + 1; int count_len_Plus1 = n % m; int count_len = m - count_len_Plus1; return Math.pow(len, count_len) * Math.pow(len_Plus1, count_len_Plus1); } }
classSolution{ publicintcuttingRope(int n){ if(n <= 3) return n - 1; else { long ans = 0L; int m = n / 3; int remain = n % 3; int c = 1000000007; if(remain == 0) { ans = pow(3, m, c); } elseif(remain == 1) { ans = pow(3, m-1, c) * 4 % c; } else { ans = pow(3, m, c) * 2 % c; } return (int) ans; } }
privatelongpow(int a, int b, int c) { if(b == 0) return1; if(b == 1) return a % c; if((b & 1) == 0) return pow(a, b/2, c) * pow(a, b/2, c) % c; else return (pow(a, b/2, c) * a % c) * pow(a, b/2, c) % c; } }
从a的1次幂开始, 如果n末尾为0, 就说明没有a的1次幂, ans不变, a变为a * a. n = n / 2.
现在n = 5, 末尾为1, a = a0^2, 说明有1个a的2次幂, *ans = a, 再次更新a变为a * a. n = n / 2.
现在n = 2, 末尾为0, a = a0^4, 说明没有a的4次幂, ans不变, 再次更新a变为a * a. n = n / 2.
现在n = 1, 末尾为1, a = a0^8, 说明有1个a的8次幂, *ans = a, 再次更新a变为a * a. n = n / 2.
现在 n = 0, 结束循环.
从上面看出, ans 与a0^2相乘过一次, 与a0^8相乘一次, 刚好为a0^10.
这种方法应该是快速幂最优解法了, 对数复杂度, 常数空间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
privatelongpow(int a0, int b, int c) { long a = a0; if(b < 0) return0; long ans = 1; int n = b; while(n > 0) { if((n & 1) == 1) { ans = ans * a % c; } a = a * a % c; n = n >> 1; } return ans; }
publicclassSolution{ // you need to treat n as an unsigned value publicinthammingWeight(int n){ int ans = 0; while(n != 0) { n = n & (n - 1); ++ans; } return ans; } }