开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第16天,点击查看活动详情
所有可能的真二叉树
给你一个整数 n ,请你找出所有可能含 n 个节点的 真二叉树 ,并以列表形式返回。答案中每棵树的每个节点都必须符合 Node.val == 0 。
答案的每个元素都是一棵真二叉树的根节点。你可以按 任意顺序 返回最终的真二叉树列表。
真二叉树 是一类二叉树,树中每个节点恰好有 0 或 2 个子节点。
示例1:
输入:n = 7
输出:[[0,0,0,null,null,0,0,null,null,0,0],[0,0,0,null,null,0,0,0,0],[0,0,0,0,0,0,0],
[0,0,0,0,0,null,null,null,null,0,0],[0,0,0,0,0,null,null,0,0]]
示例2:
输入: n = 3
输出: [[0,0,0]]
提示:
1 <= n <= 20
解题思路:
- 如果给定的 n 是偶数,那么直接返回空的数组,因为不能组成满二叉树,而如果只有 1 个节点,则可以返回 [node] -- 这个是边界
- 对于每一个子树而言,都是在构建满二叉树,只是对应的节点数 n 有所区别而言 -- 换句话说,对于每一个子节点,都要进行一次构建满二叉树,知道边界为止
- 每一层都是遍历分配左右树的节点数,然后使用后续遍历的方式遍历到边界条件处,然后开始进行处理;
- 只有当左右节点树都存在节点的时候,才需要进行拼接,组合成新的节点数组往上递归
- 整体就是自顶向下分配子树节点数,来求满二叉树;然后自低向上组合更新节点树,最后得到一个合规的满二叉树节点数组;
- 时间复杂度
N^2, 每一层都需要遍历切割,切割完之后分别进行树的创建
我的答案:
var allPossibleFBT = function (n) {
const recursion = (n) => {
if (n % 2 === 0) return []; // 偶数
if (n === 1) return [new TreeNode(0)];
const ret = []; // 保存当前节点下,所有满足`满二叉树`情况的节点
for (let i = 0; i < n; i++) {
const left_num = i,
right_num = n - i - 1; // 之所以再减去 1 个,因为根节点占据了 1
// 构建左树的满二叉树
const lefts = recursion(left_num);
const rights = recursion(right_num);
if (lefts && rights) {
// 必须同时存在的时候,才是满的;要不都没有
for (let l of lefts) {
for (let r of rights) {
const root = new TreeNode(0);
root.left = l;
root.right = r;
ret.push(root);
}
}
}
}
return ret;
};
return recursion(n);
};
最后
如果有更好的解法或者思路, 欢迎在评论区和我交流~ ღ( ´・ᴗ・` )