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

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

要求高效且适用性强的代码可以直接看代码3

题目

跳转到原题目
在这里插入图片描述

刚看到这道题目的时候,就想到了之前做的树的层序遍历-广度优先搜索(BFS),操作都是以“层”为单位,通过广度优先遍历将一层的节点联系起来。因此就直接对层序遍历的代码进行修改。

代码1

/*
// 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) {
        Queue<Node> queue=new ArrayDeque<>();
        if(root==null) return null;
        queue.add(root);
        
        while(!queue.isEmpty()){
            //获取该层中的元素个数
            int n=queue.size();
            for(int i=0;i<n;i++){
                //获取栈弹出的首元素
                Node node=queue.poll();
                //如果该结点存在孩子结点,就将孩子节点压入栈中,为下一层做准备
                if(node.left!=null) {
                    queue.add(node.left);
                }
                if(node.right!=null){
                	queue.add(node.right);
                //如果在该层中,这是最后一个元素,则指向null
                if(i==n-1) node.next=null;
                //如果在该层中,这不是最后一个元素,则指向下一个元素,也就是现在栈中的首元素
                else node.next=queue.peek();//注意peek()与poll()和pop()
            }
        }
        return root;       
    }
}

可能因为刚做过层次遍历,所以这种方法我最先想到,但是貌似效率不是很高在这里插入图片描述
这里贴上官方给出的使用已建立的next指针法链接和代码

代码2

class Solution {
    public Node connect(Node root) {
        
        if (root == null) {
            return root;
        }
        
        // Start with the root node. There are no next pointers
        // that need to be set up on the first level
        Node leftmost = root;
        
        // Once we reach the final level, we are done
        while (leftmost.left != null) {
            
            // Iterate the "linked list" starting from the head
            // node and using the next pointers, establish the 
            // corresponding links for the next level
            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;
                }
                
                // Progress along the list (nodes on the current level)
                head = head.next;
            }
            
            // Move onto the next level
            leftmost = leftmost.left;
        }
        
        return root;
    }
}

这个方法效率要比广度搜索要高一些,主要是执行时间少,但是对比下来,它也有缺点,代码2的适用性不如代码1,假如题目给出的不是完美二叉树,那么代码1就要分类讨论(修改代码),而代码2可以直接运行,适用于所有树的指向下一个右侧节点类型。

代码1,2都有各自缺点,那有没有既高效又有高使用性的办法呢?leedcode上大神多多,自然是有的。其实代码1耗时长的原因,是因为我们采用了了队列,一直不停的入列出列,而如果将队列换成链表,时间就大大缩小了。

详细内容可以去leetcode上看原文,这里贴上链接:广度优先搜索(BFS)与链表

代码3

    public Node connect(Node root) {
        if (root == null)
            return root;
        //cur我们可以把它看做是每一层的链表
        Node cur = root;
        while (cur != null) {
            //遍历当前层的时候,为了方便操作在下一
            //层前面添加一个哑结点(注意这里是访问
            //当前层的节点,然后把下一层的节点串起来)
            Node dummy = new Node(0);
            //pre表示访下一层节点的前一个节点
            Node pre = dummy;
            //然后开始遍历当前层的链表
            while (cur != null) {
                if (cur.left != null) {
                    //如果当前节点的左子节点不为空,就让pre节点
                    //的next指向他,也就是把它串起来
                    pre.next = cur.left;
                    //然后再更新pre
                    pre = pre.next;
                }
                //同理参照左子树
                if (cur.right != null) {
                    pre.next = cur.right;
                    pre = pre.next;
                }
                //继续访问这一行的下一个节点
                cur = cur.next;
            }
            //把下一层串联成一个链表之后,让他赋值给cur,
            //后续继续循环,直到cur为空为止
            cur = dummy.next;
        }
        return root;
    }


在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值