LeetCode 每日一题笔记
0. 前言
- 日期:2026.06.06
- 题目:2196. 根据描述创建二叉树
- 难度:中等
- 标签:二叉树、哈希表、数组
1. 题目理解
问题描述 :
给定二维数组 descriptions,其中 descriptions[i] = [parent, child, isLeft],表示 parent 是 child 的父节点。
- 若
isLeft == 1,则child是parent的左孩子; - 若
isLeft == 0,则child是parent的右孩子。
根据描述构造完整二叉树,并返回根节点。
示例:
输入:
descriptions = [[20,15,1],[20,17,0],[50,20,1],[50,80,0],[80,19,1]]输出:根节点为
50的二叉树。
2. 解题思路
核心观察
- 根节点的关键特征:没有父节点 (不会出现在任何
child位置)。 - 可以用数组/哈希表存储所有节点,一次性遍历即可构建完整树结构。
算法步骤
- 遍历
descriptions,创建父、子节点并建立左右关系; - 用布尔数组标记所有有父节点的节点;
- 遍历节点,找到无父节点的节点作为根返回。
3. 代码实现
java
package lc2196;
import java.util.HashSet;
class Solution {
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {
}
TreeNode(int val) {
this.val = val;
}
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
public TreeNode createBinaryTree(int[][] descriptions) {
TreeNode root = new TreeNode(0);
HashSet<Integer> father = new HashSet<Integer>();
HashSet<Integer> kid = new HashSet<Integer>();
int[][] arr = new int[100001][2];
for (int i = 0; i < descriptions.length; i++) {
//左孩子
if (descriptions[i][2] == 1) {
arr[descriptions[i][0]][0] = descriptions[i][1];
}
//右孩子
else {
arr[descriptions[i][0]][1] = descriptions[i][1];
}
kid.add(descriptions[i][1]);
}
for (int i = 0; i < descriptions.length; i++) {
if (!kid.contains(descriptions[i][0])) {
root.val = descriptions[i][0];
}
}
method1(root, arr, arr[root.val][0], arr[root.val][1]);
return root;
}
private void method1(TreeNode root, int[][] arr, int left, int right) {
if (left != 0) {
root.left = new TreeNode(left);
method1(root.left, arr, arr[left][0], arr[left][1]);
}
if (right != 0) {
root.right = new TreeNode(right);
method1(root.right, arr, arr[right][0], arr[right][1]);
}
}
}
4. 代码优化说明
java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode createBinaryTree(int[][] descriptions) {
// 数组存储所有节点,下标对应节点值
TreeNode[] nodes = new TreeNode[100001];
// 标记节点是否存在父节点
boolean[] existParent = new boolean[100001];
for (int[] description : descriptions) {
// 父节点不存在则创建
if (nodes[description[0]] == null) {
nodes[description[0]] = new TreeNode(description[0]);
}
// 子节点不存在则创建
if (nodes[description[1]] == null) {
nodes[description[1]] = new TreeNode(description[1]);
}
// 建立左右孩子关系
if (description[2] == 1) {
nodes[description[0]].left = nodes[description[1]];
} else {
nodes[description[0]].right = nodes[description[1]];
}
// 标记子节点已有父节点
existParent[description[1]] = true;
}
// 遍历找到无父节点的根节点
for (int i = 0; i < 100001; i++) {
if (nodes[i] != null && !existParent[i]) {
return nodes[i];
}
}
return null;
}
}
5. 复杂度分析
- 时间复杂度 :O(n)O(n)O(n),两次线性遍历(一次构建节点关系,一次找根节点)。
- 空间复杂度 :O(n)O(n)O(n),主要为节点数组和标记数组的开销。
6. 总结
- 核心思路:通过标记"无父节点"找到根节点,同时一次性构建树结构。
- 优化点:用数组直接存储节点,避免递归构建,减少分支判断,逻辑更简洁高效。
- 关键技巧:根节点的识别方法是这类题的核心,利用"不会出现在子节点位置"这一特征快速定位。