(A卷,200分)- 创建二叉树(Java & JS & Python)

题目描述

请按下列描述构建一颗二叉树,并返回该树的根节点:

1、先创建值为-1的根结点,根节点在第0层;

2、然后根据operations依次添加节点: operations[i] = [height, index] 表示对第 height 层的第index 个节点node, 添加值为 i 的子节点:

  • 若node 无「左子节点」,则添加左子节点;
  • 若node 有「左子节点」,但无「右子节点」,则添加右子节点;
  • 否则不作任何处理。

height、index 均从0开始计数;

index 指所在层的创建顺序。

注意:

  • 输入用例保证每次操作对应的节点已存在;
  • 控制台输出的内容是根据返回的树根节点,按照层序遍历二叉树打印的结果。

输入描述

operations

输出描述

根据返回的树根节点,按照层序遍历二叉树打印的结果

备注

  • 1 <= operations.length <= 100
  • operations[i].length == 2
  • 0 <= operations[i][0] < 100
  • 0 <= operations[i][1] < 100

用例

输入 [[0, 0], [0, 0], [1, 1], [1, 0], [0, 0]]
输出 [-1, 0, 1, 3, null, 2]
说明

首个值是根节点的值,也是返回值;

null 表示是空节点,此特殊层序遍历会遍历有值节点的 null 子节点

输入 [[0, 0], [1, 0], [1, 0], [2, 1], [2, 1], [2, 1], [2, 0], [3, 1], [2, 0]]
输出 [-1, 0, null, 1, 2, 6, 8, 3, 4, null, null, null, null, null, null, 7]
说明

首个值是根节点的值,也是返回值;

null 表示是空节点,此特殊层序遍历会遍历有值节点的 null 子节点

题目解析

首先,解释下上面两个用例的输入,输出

用例1含义

operations[0] = [0, 0]

即:第0行第0个创建的节点插入子节点值0

 ​​

operations[1] = [0, 0]  

即:第0行第0个创建的节点插入子节点值1

 

operations[2] = [1, 1]  

即:第1行第1个创建的节点插入子节点值2

 

operations[3] = [1, 0]  

即:第1行第0个创建的节点插入子节点值3 

 

operations[4] = [0, 0]  

即:第0行第0个创建的节点插入子节点值4,但是由于第0行第0个创建的节点左右子节点都已有了,因此不插入

 

 上图就是用例1的二叉树,输出时,由于题目说:层序遍历会遍历有值节点的 null 子节点,因此为上面二叉树的有值节点加入null子节点,如下图所示

 层序遍历结果为:-1, 0, 1, 3, null, 2, null

 但是用例输出是:[-1, 0, 1, 3, null, 2],因此最后一个null子节点可以不用输出。


用例2含义

 

 operations[0] = [0, 0]

即:第0行第0个创建的节点插入子节点值0

 operations[1] = [1, 0]

即:第1行第0个创建的节点插入子节点值1

  operations[2] = [1, 0]

即:第1行第0个创建的节点插入子节点值2

  operations[3] = [2, 1]

即:第2行第1个创建的节点插入子节点值3

  operations[4] = [2, 1]

即:第2行第1个创建的节点插入子节点值4

 operations[5] = [2, 1]

即:第2行第1个创建的节点插入子节点值5,但是由于第2行第1个创建的节点已经有了左右子节点,因此不插入

 operations[6] = [2, 0]

即:第2行第0个创建的节点插入子节点值6

 operations[7] = [3, 1]

即:第3行第1个创建的节点插入子节点值7

此时需要特别注意下,第3行第1个创建的节点是上图的值3节点吗????

为什么我要特别标注这句话呢?

因为题目中说:operations[i] = [height, index],而index 指所在层的创建顺序

 我们回到  operations[4],可以发现第3行第1个创建的节点是值4节点,而值3节点是第3行第0个创建的节点。

因此此步图示如下

 operations[8] = [2, 0]

即:第2行第0个创建的节点插入子节点值8

补充有值节点的null子节点

因此按照层序输出顺序是:

-1, 0, null, 1, 2, 6, 8, 3, 4, null, null, null, null, null, 7 

当我们了解完上面两个用例的含义后,就可以做题了。

本题的难点在于如何记录每层节点的创建顺序index,如果通过传统的二叉树结构,则很难实现,原因是:

  • 如何通过height(层数),index(该层第index个创建的)对应到二叉树的点

其中层数height可以通过层序遍历二叉树找到,但是index创建顺序却无法通过层序遍历找到,因此在构建二叉树时,还需要额外记录index到每个点自身,在层序遍历的时候,找到点,并取得它自身记录的index值,对比要查找的index值。

上面这个逻辑就非常麻烦了,因此不推荐这么做。

我的解题思路是,创建一个二维数组(集合,列表)tree,初始时为: [[node(-1)]]

即tree[0][0] = node(-1),这里tree[0][0]表示height = 0, index = 0

即tree的行索引就是height层数,列索引就是index创建顺序

tree[0][0]就代表二叉树根节点。

当我们遍历operations时,operations[i] = [height, index] ,其实就是找 tree[height][index]父节点,在该父节点下插入node(i)子节点,而在该父节点下插入node(i)子节点,其实就是向tree[height+1]数组中加入node(i)节点,比如

插入逻辑是:

  • 若tree[height][index] 无「左子节点」,则添加左子节点;
  • 若tree[height][index] 有「左子节点」,但无「右子节点」,则添加右子节点;
  • 否则不作任何处理。

如果tree[height+1]不存在,需要先初始化一个数组,然后加入node(i)节点,此时node(i)节点在tree[height+1]中的索引其实就是node(i)节点,在height+1层的index创建顺序。

这样的话,我们就能依赖于tree二维数组结构来完成任意节点的height,index的记录了。这样用例2插入值7时,就可以快速找到第3行第1个创建的节点了。

但是,此时各节点之间并没有建立连续,因此我们还要设计Node类,来完成各节点之间的父子关系构建。这个就很简单了,具体实现看代码。

2023.03.15 经网友指正,有如下用例:

[[0,0],[0,0],[1,0],[1,0],[1,0],[1,1],[1,1],[2,2]]

其中[2,2]应该对应哪个值得节点,大家可以先思考一下

 其实如果按照上面思路,值4节点应该是二叉树的第二行第二个创建的节点,但是它没有成功插入到二叉树中。

因此它不能算二叉树的第二行第二个创建的节点,值5接待你才能算上二叉树的第二行第二个创建的节点。

因此,前面tree记录节点创建顺序时,应该注意这种情况,要排除掉加入二叉树失败的节点。

JavaScript算法源码

/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

rl.on("line", (line) => {
  const operations = JSON.parse(line);
  console.log(getResult(operations));
});

function getResult(operations) {
  const tree = [[new Node(-1)]];

  for (let i = 0; i < operations.length; i++) {
    const [height, index] = operations[i];

    if (!tree[height + 1]) tree.push([]);

    const ch = new Node(i);

    const fa = tree[height][index];
    // 注意,tree用于记录树中加入成功的节点是第几行第几个创建的,对于加入的失败的不应该记录
    if (fa.lc == null || fa.rc == null) {
      tree[height + 1].push(ch);
    }

    if (!fa.lc) fa.lc = ch;
    else if (!fa.rc) fa.rc = ch;
  }

  const ans = [];
  const queue = [tree[0][0]];

  while (queue.length) {
    const node = queue.shift();

    if (node) {
      ans.push(node.val);
      queue.push(node.lc);
      queue.push(node.rc);
    } else {
      ans.push(null);
    }
  }

  while (true) {
    if (ans.at(-1) == null) ans.pop();
    else break;
  }

  return JSON.stringify(ans).replace(/,/g, ", ");
}

class Node {
  constructor(val) {
    this.val = val;
    this.lc = null;
    this.rc = null;
  }
}

Java算法源码

import java.util.*;

public class Main {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);

    String str = sc.nextLine();

    Integer[][] operations =
        Arrays.stream(str.substring(1, str.length() - 1).split("(?<=]), (?=\[)"))
            .map(
                s ->
                    Arrays.stream(s.substring(1, s.length() - 1).split(", "))
                        .map(Integer::parseInt)
                        .toArray(Integer[]::new))
            .toArray(Integer[][]::new);

    System.out.println(getResult(operations));
  }

  public static String getResult(Integer[][] operations) {
    Node head = new Node(-1);

    ArrayList<Node> level0 = new ArrayList<>();
    level0.add(head);

    ArrayList<ArrayList<Node>> tree = new ArrayList<>();
    tree.add(level0);

    for (int i = 0; i < operations.length; i++) {
      int height = operations[i][0];
      int index = operations[i][1];

      if (tree.size() <= height + 1) {
        tree.add(new ArrayList<>());
      }

      Node ch = new Node(i);

      Node fa = tree.get(height).get(index);
      // 注意,tree用于记录树中加入成功的节点是第几行第几个创建的,对于加入的失败的不应该记录
      if (fa.lc == null || fa.rc == null) {
        tree.get(height + 1).add(ch);
      }

      if (fa.lc == null) fa.lc = ch;
      else if (fa.rc == null) fa.rc = ch;
    }

    LinkedList<Integer> ans = new LinkedList<>();
    LinkedList<Node> queue = new LinkedList<>();
    queue.add(tree.get(0).get(0));

    while (queue.size() > 0) {
      Node node = queue.removeFirst();

      if (node != null) {
        ans.add(node.val);
        queue.add(node.lc);
        queue.add(node.rc);
      } else {
        ans.add(null);
      }
    }

    while (true) {
      if (ans.getLast() == null) ans.removeLast();
      else break;
    }

    StringJoiner sj = new StringJoiner(", ", "[", "]");
    for (Integer an : ans) {
      sj.add(an + "");
    }

    return sj.toString();
  }
}

class Node {
  int val;
  Node lc;
  Node rc;

  public Node(int val) {
    this.val = val;
    this.lc = null;
    this.rc = null;
  }
}

Python算法源码

# 输入获取
operations = eval(input())


class Node:
    def __init__(self, val):
        self.val = val
        self.lc = None
        self.rc = None


# 算法入口
def getResult(operations):
    tree = [[Node(-1)]]

    for i in range(len(operations)):
        height, index = operations[i]

        if len(tree) <= height + 1:
            tree.append([])

        ch = Node(i)

        fa = tree[height][index]
        # 注意,tree用于记录树中加入成功的节点是第几行第几个创建的,对于加入的失败的不应该记录
        if not fa.lc or not fa.rc:
            tree[height + 1].append(ch)

        if not fa.lc:
            fa.lc = ch
        elif not fa.rc:
            fa.rc = ch

    ans = []
    queue = [tree[0][0]]

    while len(queue) > 0:
        node = queue.pop(0)

        if node is not None:
            ans.append(node.val)
            queue.append(node.lc)
            queue.append(node.rc)
        else:
            ans.append("null")

    while True:
        if ans[-1] == "null":
            ans.pop()
        else:
            break

    return ans


# 算法调用
res = str(getResult(operations))
print(res.replace("'", ""))

免责声明:

1、IT资源小站为非营利性网站,全站所有资料仅供网友个人学习使用,禁止商用
2、本站所有文档、视频、书籍等资料均由网友分享,本站只负责收集不承担任何技术及版权问题
3、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除下载链接并致以最深的歉意
4、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
5、一经注册为本站会员,一律视为同意网站规定,本站管理员及版主有权禁止违规用户
6、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和IT资源小站的同意
7、IT资源小站管理员和版主有权不事先通知发贴者而删除本文

0

评论0

站点公告

没有账号?注册  忘记密码?