东哥带你刷二叉搜索树(构造篇) :: labuladong的算法小抄 #1413
Replies: 20 comments 3 replies
-
95 题「不同的二叉搜索树 II 这道题还是需要memo的吧, 可以提速 |
Beta Was this translation helpful? Give feedback.
-
看不懂这个base case 呜呜 |
Beta Was this translation helpful? Give feedback.
-
这里的 memo 应该不需要二维数组,就类似于斐波那契数列那种感觉,memo[i] 可以表示为节点数为 i 的 BST 的数量。 |
Beta Was this translation helpful? Give feedback.
-
我个人感觉第二题不太能memo,如果最后需要各个树节点不共用的话 |
Beta Was this translation helpful? Give feedback.
-
第二题如果需要memo的话空间复杂度会提升 因为存的不是个数 而是实打实的节点 |
Beta Was this translation helpful? Give feedback.
-
@labuladong,有没有这个系列的一个专用的qq讨论群,或者微信讨论群,或者可以建一个吗?感觉自己理解了但是不交流就很难内化。 |
Beta Was this translation helpful? Give feedback.
-
@Jackwong0716 可以参加 刷题打卡挑战,讨论氛围比较好。 |
Beta Was this translation helpful? Give feedback.
-
我写的缓存版 var generateTrees = function (n) {
const cache = {
0: [null],
1: [new TreeNode(1)],
};
function fn(start, end) {
if (start > end) {
return [null];
}
const key = `${start}_${end}`;
if (cache[key]) {
return cache[key];
}
if (start === end) {
const root = new TreeNode(start);
cache[key] = [root];
return [root];
}
const res = [];
for (let i = start; i <= end; i++) {
const leftArr = fn(start, i - 1);
const rightArr = fn(i + 1, end);
leftArr.forEach(leftItem => {
rightArr.forEach(rightItem => {
const root = new TreeNode(i);
root.left = leftItem;
root.right = rightItem;
res.push(root);
});
});
}
cache[key] = res;
return res;
}
return fn(1, n);
}; |
Beta Was this translation helpful? Give feedback.
-
var numTrees = function(n) {
// 新建备忘录
const memo = new Array(n + 1).fill().map(() => new Array(n + 1));
// 计算闭区间[1, n]组成的BST个数
return count(1, n);
/* 计算闭区间[lo, hi]组成的BST个数 */
function count(lo, hi) {
// base case
if (lo >= hi) {
return 1;
}
// 查备忘录
if (memo[lo][hi]) {
return memo[lo][hi];
}
let res = 0;
for (let i=lo; i<=hi; i++) {
// i的值作为根节点root
let left = count(lo, i - 1);
let right = count(i + 1, hi);
// 左右子树的组合数乘积是BST的总数
res += left * right;
}
// 将结果存入备忘录
memo[lo][hi] = res;
return res;
}
}; |
Beta Was this translation helpful? Give feedback.
-
var generateTrees = function(n) {
if (n == 0) return [];
// 构造备忘录 避免重复计算
let memo = new Map();
/* 构造闭区间[1, n]组成的BST */
return build(1, n);
/* 构造闭区间[lo, hi]组成的BST */
function build(lo, hi) {
// base case 空节点null
let res = [];
if (lo > hi) {
res.push(null);
return res;
}
// 新建备忘录关键字
let memoKey = `${lo}&${hi}`;
// 查询备忘录
if (memo.has(memoKey)) {
return memo.get(memoKey);
}
// 1、穷举root节点组成的所有BST可能
for (let i=lo; i<= hi; i++) {
// 2、递归构造出左右子树的所有合法BST
let leftTree = build(lo, i - 1);
let rightTree = build(i + 1, hi);
// 3、给root节点穷举所有左右子树的组合
for (let left of leftTree) {
for (let right of rightTree) {
// i作为根节点root的值
res.push(new TreeNode(i, left, right));
}
}
}
// 将结果存入备忘录
memo.set(memoKey, res);
return res;
}
}; |
Beta Was this translation helpful? Give feedback.
-
不同的二叉树并不需要计算在哪个区间有多少棵二叉树,只要区间的长度是固定的,那么结果一定也相同,因此写成这样即可 |
Beta Was this translation helpful? Give feedback.
-
刷这篇是不是应该先刷动态规划?感觉有点儿吃力…… |
Beta Was this translation helpful? Give feedback.
-
带备忘录的不同二叉搜索树2,java版
|
Beta Was this translation helpful? Give feedback.
-
top-down太難了想不到,這題感覺bottom-up的dp容易理解一點 /**
* @param {number} n
* @return {number}
*/
var numTrees = function(n) {
// init dp array, fill with 1 as base case for n = 0 or 1 are both 1
let dp = new Array(n+1).fill().map(e=>1)
// STATE: how many nodes we use to make a tree
// start from 2 as we already have the base case value set
for (let nodes = 2; nodes <= n; nodes++) {
let total = 0
// CHOICE: for certain number of nodes, use either one of them as the root node
// start from 1 as the unique value is from 1 to n
for (let root = 1; root <= nodes; root++) {
// left is the nodes count on the left side of current root
// e.g. when nodes = 5 and root = 2, we use 1, 2, 3, 4, 5 to create a BST
// there are 2 - 1 nodes on 2's left, 5 - 2 nodes on 2's right
let left = root - 1
let right = nodes - root
// total count is the combination/Cartesian product of left and right
total += dp[left] * dp[right]
}
// save the result for current node
dp[nodes] = total
}
return dp[n]
} |
Beta Was this translation helpful? Give feedback.
-
不同二叉搜索树, 一维memo. class Solution {
int[] memo;
public int numTrees(int n) {
memo = new int[n + 1];
return count(1, n);
}
public int count(int lo, int hi) {
if(memo[hi - lo + 1] != 0) return memo[hi - lo + 1];
if(lo > hi) return 1;
int res = 0;
for(int i = lo; i <= hi; i++) {
int left = count(lo, i - 1);
int right = count(i + 1, hi);
res += left * right;
}
memo[hi - lo + 1] = res;
return res;
}
} |
Beta Was this translation helpful? Give feedback.
-
做了这么多二叉树的题,还是难以相信计算机中居然有递归这么<唯心主义>的算法,定义一个方法,坚定地相信它能完成一项功能,然后递归调用就行,完全没法考虑它到底是怎么实现的 |
Beta Was this translation helpful? Give feedback.
-
bottom-up solution: class Solution {
public int numTrees(int n) {
// transition equation:
// f[n] = sum{ f[i] * f[n-i] } , for i in [1..n]
// 即 i依次选择节点1..n为根时,左子树的种类数 f[i] * 右子树的种类数 f[n-i]
// base case: f[0] = 1,相当于没有节点时的数目
int[] f = new int[n+1];
f[0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
f[i] += f[j - 1] * f[i - j];
}
}
return f[n];
}
} |
Beta Was this translation helpful? Give feedback.
-
对lc 95补充memo解法: class Solution {
private:
vector<vector<vector<TreeNode*>>> memo;
public:
/* 主函数 */
vector<TreeNode*> generateTrees(int n) {
memo=vector<vector<vector<TreeNode*>>> (n+1,vector<vector<TreeNode*>> (n+1));
// 定义:由[1, n]区间,具体组成的BST答案
return build(1, n);
}
vector<TreeNode*> build(int lo, int hi) {
//每次的初始化
vector<TreeNode*> res;
if (lo > hi) {
res.push_back(nullptr);//nullptr也是一个BFS
return res;
}
if(!memo[lo][hi].empty())return memo[lo][hi];
// 1、穷举 root 节点的所有可能。
for (int i = lo; i <= hi; i++) {
// 2、递归构造出 左(右)子树 本身的 所有具体BST。
vector<TreeNode*> leftTree = build(lo, i - 1);
vector<TreeNode*> rightTree = build(i + 1, hi);
// 3、根据 左(右)子树 本身的 所有具体BST->生成root节点 的 所有BST组合。
for (auto left : leftTree) {
for (auto right : rightTree) {
// i 作为根节点 root 的值
TreeNode* root = new TreeNode(i);
root->left = left;
root->right = right;
res.push_back(root);
}
}
}
memo[lo][hi]=res;
return res;
}
}; |
Beta Was this translation helpful? Give feedback.
-
文章链接点这里:东哥带你刷二叉搜索树(构造篇)
评论礼仪 见这里,违者直接拉黑。
Beta Was this translation helpful? Give feedback.
All reactions