https://leetcode.com/problems/populating-next-right-pointers-in-each-node-ii/
Follow up for problem "Populating Next Right Pointers in Each Node".
What if the given tree could be any binary tree? Would your previous solution still work?
Note:
- You may only use constant extra space.
For example,
Given the following binary tree,
1 / \ 2 3 / \ \ 4 5 7
After calling your function, the tree should look like:
1 -> NULL / \ 2 -> 3 -> NULL / \ \ 4-> 5 -> 7 -> NULL
解题思路:
先给出一个level order traversal的方法,虽然不符合题目要求的constant space,不过贵在简单。
这种在层次遍历时要求区分每层,在每层内做操作的题目已经出现好多了,方法就是用一个变量去存当前层次的size。下面多出的两个问题,第一,用两个指针指向同一层次的前后两个节点,把前面节点的next指向后面的即可。第二,遇到最后一个节点,这里用levelSize == 0来判断,next指向null。
/** * Definition for binary tree with next pointer. * public class TreeLinkNode { * int val; * TreeLinkNode left, right, next; * TreeLinkNode(int x) { val = x; } * } */ public class Solution { public void connect(TreeLinkNode root) { Queue<TreeLinkNode> queue = new LinkedList<TreeLinkNode>(); if(root == null){ return; } queue.offer(root); while(queue.size() != 0){ int levelSize = queue.size(); TreeLinkNode preNode = null; while(levelSize > 0){ TreeLinkNode currentNode = queue.poll(); if(currentNode.left != null){ queue.offer(currentNode.left); } if(currentNode.right != null){ queue.offer(currentNode.right); } //层序遍历,本层前一个node指向后一个node if(preNode != null){ preNode.next = currentNode; } preNode = currentNode; levelSize--; //本层最后一个node指向null if(levelSize == 0){ currentNode.next = null; } } } } }
下面考虑题目的要求,使用constant space。上一个问题Populating Next Right Pointers in Each Node中,将root.left.next设置为root.right,root.right.next设置为root.next.left。这里由于不是一个完全二叉树,左右子树都有可能为空。所以只有在root.right !=null的时候,root.left.next才能置为root.right。否则就需要看root右侧的节点,即root.next的左右子树。如果root.next不为空,但是它的左右子树都是空的,就再向右看。
处理root.right也是一样的道理。
需要注意的是递归的顺序,必须先递归右子树,再递归左子树。如果反过来的话,右子树还未处理,这样root.next很可能是空的,就是横向的链接还没建立,就无法指向正确的节点了。
/** * Definition for binary tree with next pointer. * public class TreeLinkNode { * int val; * TreeLinkNode left, right, next; * TreeLinkNode(int x) { val = x; } * } */ public class Solution { public void connect(TreeLinkNode root) { if(root == null){ return; } if(root.left != null){ if(root.right != null){ root.left.next = root.right; }else{ TreeLinkNode next = root.next; //如果next不为null,但都没有左右子树,则继续往右取next while(next != null && next.left == null && next.right == null){ next = next.next; } if(next == null){ root.left.next = null; }else{ if(next.left != null){ root.left.next = next.left; }else{ if(next.right != null){ root.left.next = next.right; } } } } } if(root.right != null){ TreeLinkNode next = root.next; while(next != null && next.left == null && next.right == null){ next = next.next; } if(next == null){ root.right.next = null; }else{ if(next.left != null){ root.right.next = next.left; }else{ if(next.right != null){ root.right.next = next.right; } } } } //必须先处理右子树,再处理左子树。否则可能此时root.next还未赋值,还是null connect(root.right); connect(root.left); } }
下面将这个解法改成迭代。处理具体节点的方法不变,无非就是循环的条件。
这里,每一层root都用root.next去迭代它,每层循环终止的条件是,root==null。这时去找下一层的第一个节点,如何找?在该层中,找到第一个本身不为空,而且有左子树或者右子树的节点,将它的左子树或者右子树作为下一层的第一个节点。然后进入内层循环处理该层。
外层循环结束的条件是,找不到下一层的处理节点,即下一层的第一个节点为null。
/** * Definition for binary tree with next pointer. * public class TreeLinkNode { * int val; * TreeLinkNode left, right, next; * TreeLinkNode(int x) { val = x; } * } */ public class Solution { public void connect(TreeLinkNode root) { if (root == null) { return; } TreeLinkNode nextLevelHead = root; while (nextLevelHead != null) { while (root != null) { if (root.left != null) { if (root.right != null) { root.left.next = root.right; } else { TreeLinkNode next = root.next; //如果next不为null,但都没有左右子树,则继续往右取next while (next != null && next.left == null && next.right == null) { next = next.next; } if (next == null) { root.left.next = null; } else { if (next.left != null) { root.left.next = next.left; } else { if (next.right != null) { root.left.next = next.right; } } } } } if (root.right != null) { TreeLinkNode next = root.next; while (next != null && next.left == null && next.right == null) { next = next.next; } if (next == null) { root.right.next = null; } else { if (next.left != null) { root.right.next = next.left; } else { if (next.right != null) { root.right.next = next.right; } } } } root = root.next; } //root.next已经为null,寻找下一层的头节点。道理同上,一直往右找到有左右子树的节点作为root while (nextLevelHead != null && nextLevelHead.left == null && nextLevelHead.right == null) { nextLevelHead = nextLevelHead.next; } if(nextLevelHead == null){ return; } if (nextLevelHead.left != null) { nextLevelHead = nextLevelHead.left; } else { nextLevelHead = nextLevelHead.right; } root = nextLevelHead; } } }
update 2015/05/17:
上面的解法都是寻找当前节点next指向的下一个节点,所以要循环获取。
改变一下思路,保存上一节点pre,遇见当前节点,将pre.next指向当前不就行了?这样一来,代码极为简化。pre和nextLevelFirst就取当前层次中,第一个非null的就可以。想到这个思路,是因为这个题目其实就是类似链表,next指向下一个元素。
/** * Definition for binary tree with next pointer. * public class TreeLinkNode { * int val; * TreeLinkNode left, right, next; * TreeLinkNode(int x) { val = x; } * } */ public class Solution { public void connect(TreeLinkNode root) { if(root == null) { return; } TreeLinkNode nextLevelFirst = root.left; if(nextLevelFirst == null) { nextLevelFirst = root.right; } TreeLinkNode pre = null; while(root != null) { if(root.left != null) { if(nextLevelFirst == null) { nextLevelFirst = root.left; } if(pre != null) { pre.next = root.left; pre = root.left; } else { pre = root.left; } } if(root.right != null) { if(nextLevelFirst == null) { nextLevelFirst = root.right; } if(pre != null) { pre.next = root.right; pre = root.right; } else { pre = root.right; } } if(root.next != null) { root = root.next; } else { root = nextLevelFirst; nextLevelFirst = null; pre = null; } } } }
//20180810 递归的简化代码
/** * Definition for binary tree with next pointer. * public class TreeLinkNode { * int val; * TreeLinkNode left, right, next; * TreeLinkNode(int x) { val = x; } * } */ public class Solution { public void connect(TreeLinkNode root) { if (root == null) { return; } TreeLinkNode next = root.next; while (next != null && next.left == null && next.right == null) { next = next.next; } if (root.left != null) { if (root.right == null) { if (next != null){ if (next.left != null) { root.left.next = next.left; } else { root.left.next = next.right; } } } else { root.left.next = root.right; } } if (root.right != null) { if (next != null){ if (next.left != null) { root.right.next = next.left; } else { root.right.next = next.right; } } } connect(root.right); connect(root.left); } }