「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」。
题目
链接:leetcode-cn.com/problems/un…
给你一个整数 n ,请你生成并返回所有由 n 个节点组成且节点值从 1 到 n 互不相同的不同 二叉搜索树 。可以按 任意顺序 返回答案。
示例 1:
**输入:**n = 3 输出:[[1,null,2,null,3],[1,null,3,2],[2,1,3],[3,1,null,null,2],[3,2,null,1]]
示例 2:
**输入:**n = 1 输出:[[1]]
提示:
1 <= n <= 8
思路
类似 96. 不同的二叉搜索树:求以 1 ... n 为节点组成的BST有多少种。这道题是让你构建出所有可能的BST
- 按照 BST 的定义,如果整数 i 作为根节点,则整数 1 ~ i-1 会去构建左子树,i+1 ~ n 会去构建右子树
- 以 i 为根节点的 BST 种类数 = 左子树 BST 种类数 * 右子树 BST 种类数
- 所以,不同的 i 之下,左右 BST 子树任意搭配出不同的组合,就构成了不同的 BST
代码
const generateTrees = (n) => {
if (n == 0) return [];
const getAllBSTs = (low, high) => {
if (low > high) return [null];
if (low == high) return [new TreeNode(low)];
const res = [];
for (let i = low; i <= high; i++) {
const leftBSTs = getAllBSTs(low, i - 1);
const rightBSTs = getAllBSTs(i + 1, high);
for (const leftBST of leftBSTs) {
for (const rightBST of rightBSTs) {
const root = new TreeNode(i);
root.left = leftBST;
root.right = rightBST;
res.push(root);
}
}
}
return res;
};
return getAllBSTs(1, n);
};
记忆化递归 代码
const generateTrees = (n) => {
if (n == 0) return [];
const memo = new Array(n + 1);
for (let i = 0; i < memo.length; i++) {
memo[i] = new Array(n + 1);
}
const getAllBSTs = (low, high) => {
if (low > high) return [null];
if (memo[low][high]) return memo[low][high];
if (low == high) return [new TreeNode(low)];
const res = [];
for (let i = low; i <= high; i++) {
const leftBSTs = getAllBSTs(low, i - 1);
const rightBSTs = getAllBSTs(i + 1, high);
for (const leftBST of leftBSTs) {
for (const rightBST of rightBSTs) {
const root = new TreeNode(i);
root.left = leftBST;
root.right = rightBST;
res.push(root);
}
}
}
return memo[low][high] = res;
};
return getAllBSTs(1, n);
};
其他思路,看代码
/**
* @param {number} n
* @return {TreeNode[]}
*/
// BST的创建 选择考虑这两种情况
// 左子树和右子树的划分 一层for
// 左子树集合和右子树集合的组合 2层for
var generateTrees = function (n) {
function buildTree(start, end) {
let _result = []
// 指针交错递归终止
if (start > end) return [null] // 原来如此
// i指针滑动,枚举left和right分段的所有可能
for (let i = start; i <= end; i++) {
// 左侧和右侧生成树的集合 返回为数组
let left = buildTree(start, i - 1)
let right = buildTree(i + 1, end)
// 循环左右两侧的树集合 分别拼接到新树上,并且存储到结果数组中
// 从左子树集合中选出一棵左子树,从右子树集合中选出一棵右子树,拼接到根节点上
for (const leftNode of left) {
// left为空是这样的[null] 还是可以进来这个循环的 因为有这种场景你要想通 1==>2==>3 都是右子节点的情况
for (const rightNode of right) {
let node = new TreeNode(i)
node.left = leftNode
node.right = rightNode
_result.push(node)
}
}
}
// 返回指定范围生成的树集合
return _result
}
// n 为 0 是返回[]
if (n === 0) return []
// 指定最大范围
return buildTree(1, n)
}