这道题乍一看感觉彷佛没思路,例如要切多少段绳子,每段绳子的长度是多少才能让绳子段数乘积最大,似乎组合性太多了,根本找不出来。但是可以换一个角度(动态规划),定义一个函数y=f(n),表示绳子长度为n时,满足题目要求的最大值。比如f(12),就表示绳子长度为12时,题目要求的最大值就是这个。
动态规划一般都会用到数组来记录每一个f(n)的值,并且计算过程是从下向上的,我们一般可以从题目或手动计算一些初始信息,比如f(0),f(1), f(2)等等,然后根据f(n)和f(n-1),f(n-2)来计算出f(n)的值。这里有点类似于斐波那契额书列和青蛙跳台阶那样的计算过程。重点是找到一种关系,f(n) 与f(n-1) 或者 f(n-2)等等的运算关系,即f(n) = F(f(n-1), f(n-2),...);
这道题,可以这样想,f(n) = f(n-i) * f(i),即将长度为n的绳子分成n-i和i的两段绳子长,但是我们不知道i为多少时可以取得最大值,所以需要来一次循环,让i=1一直到i=n/2,(可以到n,但是当i > n/2时就重复计算了,没必要),同时让一个辅助变量max去记录每一个这一轮循环中的最大值,最后把max赋值给f(n)。当然计算f(n)也需要一个循环。
还有一点特殊之处在于,如果当绳子的长度初始就是2, 3时,因为虽然此时他们本身的长度就是最大值,但是题目要求必须要切,所以此时,n = 2时max = 1, n = 3时max = 2。但是绳子被切分之后,剩下的绳子长度为2,3时,由于之前已经切过一次,所以此时可以不切,最大值就是2,3.因此我们在对初始值的处理中,n = 2, n = 3要进行特殊处理,返回特殊值。但是dp矩阵中,对应的n = 2,n = 3要选择最大值。
PS:当数据量很大,需要求模时,这种思路的代码我还没有搞出来。那种情况需要用到数学推导,面向答案编程。我在减绳子II中会写道。
代码如下:
class Solution {
public int cuttingRope(int n) {
if (n < 2) return -1;//必须要切,所以长度小于2的绳子不符合要求
//当n小于等于3时,虽然本身就为最大值,但是题意必须切,所以单独处理
if (n <= 3) return n - 1;
int[] dp = new int[n + 1];
dp[1] = 1;
dp[2] = 2;
dp[3] = 3;
int max = 0;
//开始从下向上计算dp数组
for (int i = 4; i <= n; i++) {
for (int j = 1; j <= i / 2; j++) {
max = Math.max(max, dp[i - j] * dp[j]);
}
dp[i] = max;
}
return dp[n];
}
}