leetcode-zgd-day41-343.整数拆分/96.不同的二叉搜索树

76 阅读2分钟

343.整数拆分

题目链接:343. 整数拆分 - 力扣(LeetCode)

解题思路:

这个题主要还是在于这个递推公式,为什么是dp[i] = max(dp[i], dp[i - j] * j, (i - j) * j)

而不是dp[i] = max(dp[i], dp[i - j] * dp[j], (i - j) * j)

原因是因为j是从1一直向上增的,拆分j的情况,我们在之前的遍历过程中已经计算过了。所以这里拆完的j并不需要继续拆分。他已经成为了拆分之后乘积中的一个数字成员。

 class Solution {
     public int integerBreak(int n) {
         /**
          * 1.dp[i] 数字i拆分之后可以获得的最大乘积
          * 2.dp[i] = max(dp[i], dp[i - j] * j, (i - j) * j)
          * 3.dp[2] = 1
          * 4.肯定是正向循环
          */
         int[] dp = new int[n + 1];
         dp[2] = 1;
         for(int i = 3; i <= n; i++){
             dp[i] = i - 1;
             for(int j = 2; j <= i - j; j++){
                 dp[i] = Math.max(dp[i], Math.max(dp[i - j] * j, (i - j) * j));
             }
         }
         return dp[n];
     }
 }

96.不同的二叉搜索树

题目链接:96. 不同的二叉搜索树 - 力扣(LeetCode)

解题思路:

这个题也是第一时间没想到递推关系式:

应该想到以不同结点为根节点来区分不同情况的。

还有一个关机点在于:dp[1]其实也可以包含在循环内,没有必要将他拿出来单独处理。

 class Solution {
     public int numTrees(int n) {
         /**
          * 1.dp[i] i个结点的二叉搜索树种类
          * 2.dp[i] += dp[j - 1] * dp[i - j]
          * 3.dp[1] = 1 dp[2] = 2
          * 4.正向遍历
          */
         if(n == 1 || n == 2) return n;
         int[] dp = new int[n + 1];
         dp[0] = 1;
         dp[1] = 1;
         for(int i = 2; i <= n; i++){
             for(int j = 1; j <= i; j++){
                 dp[i] += dp[j - 1] * dp[i - j];
             }
         }
         return dp[n];
     }
 }

改进代码:

 class Solution {
     public int numTrees(int n) {
         /**
          * 1.dp[i] i个结点的二叉搜索树种类
          * 2.dp[i] += dp[j - 1] * dp[i - j]
          * 3.dp[1] = 1 dp[2] = 2
          * 4.正向遍历
          */
         int[] dp = new int[n + 1];
         dp[0] = 1;
         for(int i = 1; i <= n; i++){
             for(int j = 1; j <= i; j++){
                 dp[i] += dp[j - 1] * dp[i - j];
             }
         }
         return dp[n];
     }
 }