难度**

中等

思路

递归思想

  • 递推式 F(n) = Max(i*(n-i), i * F(n-i))
  • i*(n-i) 表示当前绳子由 in-i 两部分构成,且都不可继续拆分。
  • i*F(n-i) 表示当前绳子由 in-i 两部分构成,而 n-i 部分可以继续拆分。

递归_剪绳子.png

  1. /**
  2. * 递归: F(n) = Max(i*(n-i), i*F(n-i))
  3. */
  4. public static int cuttingRope_1(int n) {
  5. if (n == 2) {
  6. return 1;
  7. }
  8. int ret = -1;
  9. for (int i = 1; i < n; i++) {
  10. ret = Math.max(ret, Math.max(i * (n - i), i * cuttingRope_1(n - i)));
  11. }
  12. return ret;
  13. }
时间复杂度 O(2__)
空间复杂度 O(2__)

动态规划

  • dp[n] = Max(dp[n], Max(i*(n-i), i * dp[n-i])); 左边表示绳子可以不用在切,而 Max(i*(n-i), i*dp[n-i]) 表示切成 i 长度,剩下的 n-i 需要继续切
  • 上述动态规划式最重要的是融入 i 这个变量,这在编程中也需要考虑如何引入这个变量,需要对此变量有一个深刻的认知。实际中,i 是一个循环变量,有 0<i<n,表示从 0~n 尝试切割,再比较两者之间谁大谁小。
    1. public static int cuttingRope_3(int n) {
    2. int[] dp = new int[n + 1];
    3. dp[2] = 1;
    4. for (int i = 3; i <= n; i++) {
    5. for (int j = 1; j < i; j++) {
    6. dp[i] = Math.max(dp[i], Math.max(j * (i - j), j * dp[i - j]));
    7. System.out.println(String.format("i:%s, j:%s, dp[i]:%s", i, j, dp[i]));
    8. }
    9. }
    10. return dp[n];
    11. }
    | 时间复杂度 | O(2__) | | —- | —- | | 空间复杂度 | O(n) |

总结

  • 递归是从上往下,因此,会有很多重复计算,而动态规划是从下往上,使用一个数组存储值,因此避免了重复计算开销。
  • 而动态规划的递推式是比较难想到的,需要做大量的题目才能了解。