填充每个节点的下一个右侧节点指针

给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:

public class Node {
    public int val;
    public Node left;
    public Node right;
    public Node next;
}

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。初始状态下,所有 next 指针都被设置为 NULL。

进阶:

  • 你只能使用常量级额外空间。
  • 使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。

示例:

注:题目的描述来源于Leetcode

解法一:二叉树的遍历时讲过层序遍历,其实这个题目可以借鉴二叉树的层序遍历的思路来进行解决。其实从上面的示例中可以看出,就是进行二叉树的层序遍历,同时把遍历到的节点从左到右依次连接即可,此种解法比较简单,直接上代码

public Node connect(Node root) {
        if (root == null) {
            return null;
        }
        Queue<Node> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            //获取这一层节点的数量
            int size = queue.size();

            for (int i = 0; i < size; ++i) {
                Node node = queue.poll();
                if (i < size - 1) {
                    //前size-1个节点逐次连接
                    node.next = queue.peek();
                }

                // 拓展下一层节点
                if (node.left != null) {
                    queue.add(node.left);
                }
                if (node.right != null) {
                    queue.add(node.right);
                }
            }
        }
        return root;
    }

此种解法的时间复杂度为O(N),空间复杂度为O(N)。

解法二:题目中限定了树是一颗完美二叉树,即每一层的节点都是满的,同时进阶中要求在O(1)的空间复杂度内解决,仔细分析树的连接方式,有两种连接方式。

第一种:如下图中的 4 和 5,节点具有相同的父节点 root,此种节点的连接方式比较简单,直接执行 root.left.next => root.right

第二种:如下图中的节点 5 和 节点 6,此种节点没有相同的父节点,但是从图中我们可以发现 

(1)此次串联的两个节点恰好是上一层的 root.right节点 和n2.left节点

(2)由图克重root.next == n2

(3)经(1)和(2)分析,即转换为root.right.next => root.next.left,所以这里我们需要保证root.next不为空就可以

(4)经过前面三步的分析和下图表明,当我们要串联第 i 层节点时,需要先完成第 i-1 层的节点串联

(5)所以我们每一次找到每一层的最左侧节点(记住是一颗完美二叉树),依次执行连接即可。

(6)经过上面的分析,代码如下。

public Node connect1(Node root) {
        if (root == null) {
            return root;
        }
        //leftNodeForLevel表示每一层的最左侧节点,初始化为root
        Node leftNodeForLevel = root;

        //只需要leftNodeForLevel.left不等于空,表示还有下一层节点
        while (leftNodeForLevel.left != null) {

            //找到每一层的最左侧节点
            Node head = leftNodeForLevel;

            while (head != null) {
                //有相同父节点的情况
                head.left.next = head.right;

                //没有相同父节点的情况
                if (head.next != null) {
                    head.right.next = head.next.left;
                }

                //需要后移一个节点
                head = head.next;
            }

            //继续处理下一层
            leftNodeForLevel = leftNodeForLevel.left;
        }
        return root;
    }

解法三:递归实现。其实就是把每一层相邻的节点串联起来,那如何定义递归函数?以及如何通过找到相邻的节点?

(1)可以定义一个递归函数connectTwoNode(Node node1,Node node2)表示串联起给定的两个节点,如下面的2 和 3。

(2)首先给定的两个节点肯定是要直接相连起来

(3)两个节点的left 节点和 right 节点肯定也要相连起来

(4)经过前面三步的分析,其实我们发现,只需要把node1 的 right 和 node2 的 left  节点相连起来就可以了。

(5)当然递归的终止条件是node1 为空 或者 node2 为空,经过上面的分析,即递归函数connectTwoNode的定义如下。

    public Node connect2(Node root) {
        if (root == null) return null;
        //把root的left节点和right节点连接
        connectTwoNode(root.left, root.right);
        return root;
    }


    /**
     * 定义:输入两个节点,将它俩连接起来
     *
     * @param node1
     * @param node2
     */
    public void connectTwoNode(Node node1, Node node2) {
        if (node1 == null || node2 == null) {
            return;
        }

        // 首先传入的两个节点肯定需要连接
        node1.next = node2;

        // 传入的两个节点的左右孩子也是得连接
        connectTwoNode(node1.left, node1.right);
        connectTwoNode(node2.left, node2.right);

        // 传入的第一个节点的right节点和第二个节点的left节点也是得连接
        connectTwoNode(node1.right, node2.left);
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值