东哥带你刷二叉搜索树(构造篇) :: labuladong的算法小抄 #1413
Replies: 20 comments 3 replies
-
95 题「不同的二叉搜索树 II 这道题还是需要memo的吧, 可以提速 |
Beta Was this translation helpful? Give feedback.
-
有点难了哈 |
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.
-
刷这篇是不是应该先刷动态规划?感觉有点儿吃力…… |
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.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
文章链接点这里:东哥带你刷二叉搜索树(构造篇)
评论礼仪 见这里,违者直接拉黑。
Beta Was this translation helpful? Give feedback.
All reactions