diff --git "a/problems/0343.\346\225\264\346\225\260\346\213\206\345\210\206.md" "b/problems/0343.\346\225\264\346\225\260\346\213\206\345\210\206.md" index c9467e361f..cbd4263118 100755 --- "a/problems/0343.\346\225\264\346\225\260\346\213\206\345\210\206.md" +++ "b/problems/0343.\346\225\264\346\225\260\346\213\206\345\210\206.md" @@ -55,7 +55,7 @@ dp[i]的定义将贯彻整个解题过程,下面哪一步想不懂了,就想 j是从1开始遍历,拆分j的情况,在遍历j的过程中其实都计算过了。那么从1遍历j,比较(i - j) * j和dp[i - j] * j 取最大的。递推公式:dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j)); -也可以这么理解,j * (i - j) 是单纯的把整数拆分为两个数相乘,而j * dp[i - j]是拆分成两个以及两个以上的个数相乘。 +也可以这么理解,j * (i - j) 是单纯的把整数拆分为两个数相乘,而j * dp[i - j]是拆分成三个以及三个以上的个数相乘。 如果定义dp[i - j] * dp[j] 也是默认将一个数强制拆成4份以及4份以上了。 @@ -99,7 +99,7 @@ for (int i = 3; i <= n ; i++) { ``` 注意 枚举j的时候,是从1开始的。从0开始的话,那么让拆分一个数拆个0,求最大乘积就没有意义了。 -j的结束条件是 j < i - 1 ,其实 j < i 也是可以的,不过可以节省一步,例如让j = i - 1,的话,其实在 j = 1的时候,这一步就已经拆出来了,重复计算,所以 j < i - 1 +j的结束条件是 j < i - 1 ,其实 j < i 也是可以的,不过可以节省一步,例如让j = i - 1,的话,其实在 j = 1的时候,这一步就已经拆出来了,重复计算,所以 j < i - 1 至于 i是从3开始,这样dp[i - j]就是dp[2]正好可以通过我们初始化的数值求出来。 @@ -113,15 +113,15 @@ for (int i = 3; i <= n ; i++) { } ``` -因为拆分一个数n 使之乘积最大,那么一定是拆分成m个近似相同的子数相乘才是最大的。 +因为拆分一个数n 使之乘积最大,那么一定是拆分成m个近似相同的子数相乘才是最大的。 -例如 6 拆成 3 * 3, 10 拆成 3 * 3 * 4。 100的话 也是拆成m个近似数组的子数 相乘才是最大的。 +例如 6 拆成 3 * 3, 10 拆成 3 * 3 * 4。 100的话 也是拆成m个近似数组的子数 相乘才是最大的。 只不过我们不知道m究竟是多少而已,但可以明确的是m一定大于等于2,既然m大于等于2,也就是 最差也应该是拆成两个相同的 可能是最大值。 那么 j 遍历,只需要遍历到 n/2 就可以,后面就没有必要遍历了,一定不是最大值。 -至于 “拆分一个数n 使之乘积最大,那么一定是拆分成m个近似相同的子数相乘才是最大的” 这个我就不去做数学证明了,感兴趣的同学,可以自己证明。 +至于 “拆分一个数n 使之乘积最大,那么一定是拆分成m个近似相同的子数相乘才是最大的” 这个我就不去做数学证明了,感兴趣的同学,可以自己证明。 5. 举例推导dp数组 @@ -275,16 +275,16 @@ class Solution: def integerBreak(self, n): dp = [0] * (n + 1) # 创建一个大小为n+1的数组来存储计算结果 dp[2] = 1 # 初始化dp[2]为1,因为当n=2时,只有一个切割方式1+1=2,乘积为1 - + # 从3开始计算,直到n for i in range(3, n + 1): # 遍历所有可能的切割点 for j in range(1, i // 2 + 1): # 计算切割点j和剩余部分(i-j)的乘积,并与之前的结果进行比较取较大值 - + dp[i] = max(dp[i], (i - j) * j, dp[i - j] * j) - + return dp[n] # 返回最终的计算结果