力扣打卡:343. 整数拆分
可能思路不是很好想到
1 + n-1
| 2 + n-2
| ...
for(int i=1; i<n; i++)
,1+n-1
| 2+n-2
等等int subAns = planA(n-i)
int subMax = Math.max(n-i, subAns)
max = Math.max(max, i * subMax);
给定一个数 10
1 + 9 | 2 + 8 | 3 + 7 | 4 + 6 | 5 + 5 | 6 + 4 | 7 + 3 等等
1
的数字又可以进行分解成两个数,i + n-i
i 从 1
开始,那么到最后一定可以分解到各种组合9
的各种分解的最大乘积值,与 9
进行比较,取大值 subMax
,不一定是各种分解中的最大值,不分解可能更大,取大值即可max
进行 取大值的比较 Math.max(max, i * subMax)
,注意此时的是 i * subMax
,此时的max记录大值8
的各种分解的最大乘积值,与 8
进行比较,取大值 subMax
,不一定是各种分解中的最大值,不分解可能更大,取大值即可9
的最大乘积值进行比较,取大值即可class Solution { public int integerBreak(int n) { // 理解原理: 每一个数都可以分解成 1 + n-1 | 2 + n-2 | 3 + n-3 .... // 同时这其中的n-1,n-2,n-3又可以重新分为小于其的最大整数和1,依次类推 // 需要考虑的是:这些数可以一直分解,直至小于2时,不能分解成两个整数的和了,那么停止 // 也就是说 // 这也就是说明了,只需要考虑两个数的情况就可以了,不需要考虑分解成三个或者是分解成四个这种场景 // 因为每个数分解成两个数之后,这两个数的又可以分解成两个数,然后再次分解成两个数,最后在范围内的分解都存在 // 那么定义一个函数,能够得到给定的数的最大乘积 // return planA(n); int[] memo = new int[n+1]; // 需要n+1的长度进行储存数据n return planB(n, memo); } public int planA(int n){ if(n < 2) return 0; // 当 n 已经小于 2, 此时不能再进行分解了, 也就是返回0 int max = 0; // 初始化为0 for(int i=1; i<n; i++){ int subAns = planA(n-i); int subMax = Math.max(n-i, subAns); max = Math.max(max, i * subMax); } return max; } // 写出了暴力递归的方式,那么自顶向下的动态规划也就是多了判断和记录的两个过程 public int planB(int n, int[] memo){ if(n < 2) return 0; // 如果此时的n小于2,那么不能再进行分解了 if(memo[n] != 0) return memo[n]; int max = 0; for(int i=1; i<n; i++){ int subAns = planB(n-i, memo); int subMax = Math.max(n-i, subAns); // 这里的意思是指: n-i 的大小 和 n-i 分解成某一些数字后的乘积的大小的对比 max = Math.max(max, i * subMax); } memo[n] = max; return memo[n]; } }