leetcode.116。各ノードの次の右側のノードポインタを入力します

各ノードの次の右側のノードポインタを入力します

問題
完全なバイナリツリーが与えられると、そのすべてのリーフノードは同じレベルにあり、各親ノードには2つの子ノードがあります。バイナリツリーは次のように定義されます。

struct Node { int val; Node * left; Node * right; Node * next; }次の各ポインターを埋めて、このポインターが次の右ノードを指すようにします。次の右側のノードが見つからない場合、次のポインタはNULLに設定されます。





初期状態では、次のすべてのポインタはNULLに設定されます。
例:
ここに写真の説明を挿入

输入:{
    
    "$id":"1","left":{
    
    "$id":"2","left":{
    
    "$id":"3","left":null,"next":null,"right":null,"val":4},"next":null,"right":{
    
    "$id":"4","left":null,"next":null,"right":null,"val":5},"val":2},"next":null,"right":{
    
    "$id":"5","left":{
    
    "$id":"6","left":null,"next":null,"right":null,"val":6},"next":null,"right":{
    
    "$id":"7","left":null,"next":null,"right":null,"val":7},"val":3},"val":1}

输出:{
    
    "$id":"1","left":{
    
    "$id":"2","left":{
    
    "$id":"3","left":null,"next":{
    
    "$id":"4","left":null,"next":{
    
    "$id":"5","left":null,"next":{
    
    "$id":"6","left":null,"next":null,"right":null,"val":7},"right":null,"val":6},"right":null,"val":5},"right":null,"val":4},"next":{
    
    "$id":"7","left":{
    
    "$ref":"5"},"next":null,"right":{
    
    "$ref":"6"},"val":3},"right":{
    
    "$ref":"4"},"val":2},"next":null,"right":{
    
    "$ref":"7"},"val":1}

解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。

促す:

  • 一定の余分なスペースのみを使用できます。
  • 再帰を使用して問題を解決することも要件を満たします。この問題で再帰プログラムが占めるスタックスペースは、追加のスペースの複雑さとしてカウントされません。

アイデア

バイナリツリーを見て、最初に考えるのは、プレオーダートラバーサルミドルオーダートラバーサルポストオーダートラバーサル、深度優先検索(DFS)、幅優先検索(BFS)です。
この問題、幅優先検索(BFS)メソッドを使用する簡単に実行できます。

    public void levelOrder(TreeNode tree) {
    
    
        if (tree == null)
            return;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(tree);//相当于把数据加入到队列尾部
        while (!queue.isEmpty()) {
    
    
            //poll方法相当于移除队列头部的元素
            TreeNode node = queue.poll();
            System.out.println(node.val);
            if (node.left != null)
                queue.add(node.left);
            if (node.right != null)
                queue.add(node.right);
        }
    }

メソッド1を取得するように変更します。

方法1:レベルトラバーサル

ここに写真の説明を挿入

class Solution {
    
    
    public Node connect(Node root) {
    
    
        if (root == null) {
    
    
            return root;
        }
        
        // 初始化队列同时将第一层节点加入队列中,即根节点
        Queue<Node> queue = new LinkedList<Node>(); 
        queue.add(root);
        
        // 外层的 while 循环迭代的是层数
        while (!queue.isEmpty()) {
    
    
            
            // 记录当前队列大小
            int size = queue.size();
            
            // 遍历这一层的所有节点
            for (int i = 0; i < size; i++) {
    
    
                
                // 从队首取出元素
                Node node = queue.poll();
                
                // 连接
                if (i < size - 1) {
    
    
                    node.next = queue.peek();
                }
                
                // 拓展下一层节点
                if (node.left != null) {
    
    
                    queue.add(node.left);
                }
                if (node.right != null) {
    
    
                    queue.add(node.right);
                }
            }
        }
        
        // 返回根节点
        return root;
    }
}

方法2:確立された次のポインターを使用する

現在のノードが左側のノードである場合、現在のノードの親ノードがわかっているので、右側のノードを簡単に接続できます(タイトルは完全なバイナリツリーであることに注意してください)。
ここに写真の説明を挿入
しかし、問題は、下の図に示すように、同じレイヤー内の2つのノードの親ノードが異なることです。
ここに写真の説明を挿入
上位レイヤーのノードが接続されている場合、上位レイヤーを介して次のノードを見つけることができますか?
ここに写真の説明を挿入
など

curr.right.next = curr.next.left;

具体的には

ルートノードから開始します。レベル0にはノードが1つしかないため、処理は必要ありません。nextポインタの下のレイヤー上のレイヤーとして確立できます。この方法の最も重要なポイントは、x +1番目のレイヤーがx番目のレイヤーにあるときにそのnextポインターを確立することですこれらの接続操作が完了したら、x + 1レイヤーに移動して、x +2レイヤーの次のポインターを確立します。
レイヤーのノードをトラバースすると、レイヤーノードnextポインターが確立されます。これにより、キューが不要になり、スペースが節約されます。次のレイヤーの左端のノードを知るたびに、そのノードから開始して、リンクされたリストをトラバースするのと同じように、このレイヤーのすべてのノードをトラバースできます。

コード

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;
    }
}

再帰

前のレベルの方法を理解していれば、dfsを理解することは難しくありません。

    public Node connect(Node root) {
    
    
        dfs(root, null);
        return root;
    }

    private void dfs(Node curr, Node next) {
    
    
        if (curr == null)
            return;
        curr.next = next;
        dfs(curr.left, curr.right);
        dfs(curr.right, curr.next == null ? null : curr.next.left);
    }

BFSと再帰を解決する4つの方法を参照してください
(最後の3つの方法はユーザーの100%を打ち負かしました)

おすすめ

転載: blog.csdn.net/e891377/article/details/109091232