算法Day41 | 343. 整数拆分,96.不同的二叉搜索树

Day41

    • 343. 整数拆分
    • 96.不同的二叉搜索树

343. 整数拆分

题目链接:343. 整数拆分
dp[i]i 拆得到的最大乘积

递推公式

  • 拆成两个数:ji-j
  • 拆成多个数:jdp[i-j],(dp[i-j]是使用上一步的拆分,因此是拆成至少两个数)
    为什么只拆分i-j,而不拆分j:因为递推公式是从头开始递归的,拆分i-j的时候,已经包含了拆分j,(递推公式都是从最小可拆分开始的)

初始化:dp {0, 0, 1, ...}

class Solution {
public:
   int integerBreak(int n) {
       vector<int> dp{0, 1, 1};
       dp.resize(n + 1);
       for (int i = 3; i < n + 1; ++i) {
           for (int j = 1; j <= i / 2/*剪枝*/; ++j) {
               dp[i] = max({dp[i], j * (i - j), j * dp[i - j]});
           }
       }
       return dp.back();
   }
};

j <= i / 2这一步骤的剪枝是因为拆分出的乘积最大值,一定是在拆分出的数相等左右得到的,比如拆分 100 100 100,一定是在 5 0 2 50^2 502 3 3 2 × 34 33^2\times34 332×34 2 5 4 25^4 254等得到的,而不是 1 × 99 1\times 99 1×99 2 × 98 2\times 98 2×98

递推公式中还要和dp[i]比较是当j遍历时,固定得到的最大dp[i]


96.不同的二叉搜索树

题目链接:96.不同的二叉搜索树
根据根节点的不同,来进一步的细分树结构。
例如 n = 3 n = 3 n=3
根节点为1,左子树为0个节点,右子树为2个节点
根节点为2,左子树为1个节点,右子树为1个节点
根节点为3,左子树为2个节点,右子树为0个节点
dp[3] = dp[0] * dp[2] + dp[1] * dp[1] + dp[2] * dp[0]

递推公式:dp[i] = dp[0] * dp[i - 1] + dp[1] * dp[i - 2] + ... + dp[i - 1] * dp[0]
初始化:dp[0] = 1
遍历顺序:从小到大

class Solution {
public:
    int numTrees(int n) {
        vector<int> dp{1};
        dp.resize(n + 1);
        for (int i = 1; i < n + 1; ++i) {
            //求和的递推公式
            for (int j = 1; j < i + 1; ++j) {
                dp[i] += dp[j - 1] * dp[i - j];
            }
        }
        return dp.back();
    }
};

你可能感兴趣的:(刷题日志,算法,leetcode,动态规划,c++)