填充每个节点的下一个右侧节点指针
要求高效且适用性强的代码可以直接看代码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;
}