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

「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战

题目描述

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

struct Node { int val; Node *left; Node *right; Node *next; } 填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。

初始状态下,所有 next 指针都被设置为 NULL。

  • 示例 1:

image.png

输入:root = [1,2,3,4,5,6,7]

输出:[1,#,2,3,#,4,5,6,7,#]

解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。序列化的输出按层序遍历排列,同一层节点由 next 指针连接,'#' 标志着每一层的结束。 来源:力扣(LeetCode)

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

题目分析

这题研究了好久,没看懂题目要表达啥,最后终于在小伙伴们的思路下才懂,算法真的令人头秃,但是刷起来还是蛮有意思的。

本题的思路如下:

  1. 因为每个节点包含左节点left,右节点right索引,可以直接将左节点left的next指向right,即可完成连接,这样就可以完成2和3、4和5、6和7进行两两连接;;
  2. 对于不是相同子节点的,我们应该怎么连接呢,比如子节点5和子节点,我们可以通过节点2的right和节点3的left进行连接;
  3. 递归上述步骤,直至出现子节点是null停止遍历。

时间复杂度:复杂度O(n),n为二叉树节点的个数。

空间复杂度:O(m),m为二叉树的高度。

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;
    public Node next;
​
    public Node() {}
    
    public Node(int _val) {
        val = _val;
    }
​
    public Node(int _val, Node _left, Node _right, Node _next) {
        val = _val;
        left = _left;
        right = _right;
        next = _next;
    }
};
*/
​
class Solution {
    public Node connect(Node root) {
        if(root == null) return null;
        //获取根节点的左右子节点
        Node left = root.left;
        Node right = root.right;
        //递归连接其他子节点
        connectTwoNode(left,right);
        return root;
    }
    
    //定义递归函数,给定两个节点将它们相连
    public void connectTwoNode(Node node1,Node node2){
        //出现空节点直接返回
        if(node1 == null || node2 == null){
            return;
        }
        //将当前两个节点关联(如2/3)
        node1.next = node2;
        
        //将相同父节点的节点相连(如4/5,6/7)
        connectTwoNode(node1.left,node1.right);
        connectTwoNode(node2.left,node2.right);
        
        //将父节点不同的子节点相连(如5、6)
        connectTwoNode(node1.right,node2.left);
    }
}
​
复制代码

官网也提供了空间复杂度更少的解法,这里直接贴出来大家研究一下:

class Solution {
    public Node connect(Node root) {
        if (root == null) {
            return root;
        }
        
        // 从根节点开始
        Node leftmost = root;
        
        while (leftmost.left != null) {
            
            // 遍历这一层节点组织成的链表,为下一层的节点更新 next 指针
            Node head = leftmost;
            
            while (head != null) {
                
                // CONNECTION 1
                head.left.next = head.right;
                
                // CONNECTION 2
                if (head.next != null) {
                    head.right.next = head.next.left;
                }
                
                // 指针向后移动
                head = head.next;
            }
            
            // 去下一层的最左的节点
            leftmost = leftmost.left;
        }
        
        return root;
    }
}
复制代码

Guess you like

Origin juejin.im/post/7031555854583201806