您的位置:首页 > Web前端 > Node.js

Populating Next Right Pointers in Each Node II

2015-03-09 21:24 246 查看
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;
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: