动态规划
解题思路
确定 dp 数组以及下标的含义:dp[i] 的含义为 1 到 i 为节点组成的二叉搜索树的个数为 dp[i];
确定递推公式:状态转移方程
dp[i] += dp[j - 1] * dp[i - j]
,j-1 为 j 为头结点左子树节点数量 (由于是二叉搜索树,左节点 < 根节点 < 右节点,则左子树数量为 j-1 个) ,i - j 为以 j 为头结点右子树节点数量 (由于是二叉搜索树,左节点 < 根节点 < 右节点,则右子树数量为 i-j 个);
- n 为 1 的时候有一棵树,n 为 2 有两棵树;
- 来看看 n 为 3 的时候
- dp[3] 就是 元素1为头结点搜索树的数量 + 元素2为头结点搜索树的数量 + 元素3为头结点搜索树的数量
如何初始化 dp 数组:
dp[0] = 1
,从递归公式上来讲,如果 dp[0] = 0 那么乘法的结果就都变成 0 了;确定遍历顺序:节点数为 i 的状态是依靠 i 之前节点数的状态,所以遍历 i 一定是从前向后遍历;
举例推导 dp 数组:
节点数量 n 0 1 2 3 4 5 1 到 i 为节点组成的二叉搜索树的个数为 dp[i] 1 1 2 5 14 42
复杂度
-
时间复杂度:
O(n^2)
; -
空间复杂度:
O(n)
;
代码实现
const numTrees = (n) => {
// 1.声明 dp 数组
let dp = new Array(n + 1).fill(0);
// 2. 初始化 dp 数组
dp[0] = 1;
dp[1] = 1;
// 3. 根据递推公式,更新矩阵 dp[i] 的值
for (let i = 2; i <= n; i++) {
for (let j = 1; j <= i; j++) {
dp[i] += dp[j - 1] * dp[i - j];
}
}
return dp[n];
};
leetcode🧑💻 343. 整数拆分
上一篇