Given a binary tree

struct Node {
int val;
Node *left;
Node *right;
Node *next;
}

Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.

Initially, all next pointers are set to NULL.

Example:

Input: {"$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":null,"next":null,"right":{"$id":"6","left":null,"next":null,"right":null,"val":7},"val":3},"val":1}

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

Explanation: Given the above binary tree (Figure A), your function should populate each next pointer to point to its next right node, just like in Figure B.

Note:

  • You may only use constant extra space.
  • Recursive approach is fine, implicit stack space does not count as extra space for this problem.

这道是之前那道 Populating Next Right Pointers in Each Node 的延续,原本的完全二叉树的条件不再满足,但是整体的思路还是很相似,仍然有递归和非递归的解法。我们先来看递归的解法,这里由于子树有可能残缺,故需要平行扫描父节点同层的节点,找到他们的左右子节点。代码如下:

解法一:

class Solution {
public:
Node* connect(Node* root) {
if (!root) return NULL;
Node *p = root->next;
while (p) {
if (p->left) {
p = p->left;
break;
}
if (p->right) {
p = p->right;
break;
}
p = p->next;
}
if (root->right) root->right->next = p;
if (root->left) root->left->next = root->right ? root->right : p;
connect(root->right);
connect(root->left);
return root;
}
};

对于非递归的方法,我惊喜的发现之前的方法直接就能用,完全不需要做任何修改,算法思路可参见之前的博客 Populating Next Right Pointers in Each Node,代码如下:

解法二:

// Non-recursion, more than constant space
class Solution {
public:
Node* connect(Node* root) {
if (!root) return NULL;
queue<Node*> q;
q.push(root);
while (!q.empty()) {
int len = q.size();
for (int i = ; i < len; ++i) {
Node *t = q.front(); q.pop();
if (i < len - ) t->next = q.front();
if (t->left) q.push(t->left);
if (t->right) q.push(t->right);
}
}
return root;
}
};

虽然以上的两种方法都能通过OJ,但其实它们都不符合题目的要求,题目说只能使用constant space,可是OJ却没有写专门检测space使用情况的test,那么下面贴上constant space的解法,这个解法也是用的层序遍历,只不过没有使用queue了,我们建立一个dummy结点来指向每层的首结点的前一个结点,然后指针cur用来遍历这一层,我们实际上是遍历一层,然后连下一层的next,首先从根结点开始,如果左子结点存在,那么cur的next连上左子结点,然后cur指向其next指针;如果root的右子结点存在,那么cur的next连上右子结点,然后cur指向其next指针。此时root的左右子结点都连上了,此时root向右平移一位,指向其next指针,如果此时root不存在了,说明当前层已经遍历完了,我们重置cur为dummy结点,root此时为dummy->next,即下一层的首结点,然后dummy的next指针清空,或者也可以将cur的next指针清空,因为前面已经将cur赋值为dummy了。那么现在想一想,为什么要清空?因为我们用dummy的目的就是要指到下一行的首结点的位置即dummy->next,而一旦将root赋值为dummy->next了之后,这个dummy的使命就已经完成了,必须要断开,如果不断开的话,那么假设现在root是叶结点了,那么while循环还会执行,不会进入前两个if,然后root右移赋空之后,会进入最后一个if,之前没有断开dummy->next的话,那么root又指向之前的叶结点了,死循环诞生了,跪了。所以一定要记得清空哦,呵呵哒~

这里再来说下dummy结点是怎样指向每层的首结点的前一个结点的,过程是这样的,dummy是创建出来的一个新的结点,其目的是为了指向root结点的下一层的首结点的前一个,具体是这么做到的呢,主要是靠cur指针,首先cur指向dummy,然后cur再连上root下一层的首结点,这样dummy也就连上了。然后当root层遍历完了之后,root需要往下移动一层,这样dummy结点之后连接的位置就正好赋值给root,然后cur再指向dummy,dummy之后断开,这样又回到了初始状态,以此往复就可以都连上了,代码如下:

解法三:

// Non-recursion, constant space
class Solution {
public:
Node* connect(Node* root) {
Node *dummy = new Node(, NULL, NULL, NULL), *cur = dummy, *head = root;
while (root) {
if (root->left) {
cur->next = root->left;
cur = cur->next;
}
if (root->right) {
cur->next = root->right;
cur = cur->next;
}
root = root->next;
if (!root) {
cur = dummy;
root = dummy->next;
dummy->next = NULL;
}
}
return head;
}
};

类似题目:

Populating Next Right Pointers in Each Node

参考资料:

https://leetcode.com/problems/populating-next-right-pointers-in-each-node-ii/

https://leetcode.com/problems/populating-next-right-pointers-in-each-node-ii/discuss/37813/java-solution-with-constant-space

https://leetcode.com/problems/populating-next-right-pointers-in-each-node-ii/discuss/37828/o1-space-on-complexity-iterative-solution

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Populating Next Right Pointers in Each Node II 每个节点的右向指针之二的更多相关文章

  1. [LeetCode] 117. Populating Next Right Pointers in Each Node II 每个节点的右向指针 II

    Follow up for problem "Populating Next Right Pointers in Each Node". What if the given tre ...

  2. 117 Populating Next Right Pointers in Each Node II 每个节点的右向指针 II

    这是“每个节点的右向指针”问题的进阶.如果给定的树可以是任何二叉树,该怎么办?你以前的解决方案仍然有效吗?注意:    你只能使用恒定的空间.例如,给定以下二叉树,         1       / ...

  3. LeetCode: Populating Next Right Pointers in Each Node II 解题报告

    Populating Next Right Pointers in Each Node IIFollow up for problem "Populating Next Right Poin ...

  4. LeetCode——Populating Next Right Pointers in Each Node II

    Follow up for problem "Populating Next Right Pointers in Each Node". What if the given tre ...

  5. [leetcode]Populating Next Right Pointers in Each Node II @ Python

    原题地址:https://oj.leetcode.com/problems/populating-next-right-pointers-in-each-node-ii/ 题意: Follow up ...

  6. LeetCode - Populating Next Right Pointers in Each Node II

    题目: Follow up for problem "Populating Next Right Pointers in Each Node". What if the given ...

  7. [LeetCode] [LeetCode] Populating Next Right Pointers in Each Node II

    Follow up for problem "Populating Next Right Pointers in Each Node". What if the given tre ...

  8. leetCode 116.Populating Next Right Pointers in Each Node (为节点填充右指针) 解题思路和方法

    Given a binary tree struct TreeLinkNode { TreeLinkNode *left; TreeLinkNode *right; TreeLinkNode *nex ...

  9. [Leetcode] Populating next right pointer in each node 填充每个节点的右指针

    Given a binary tree struct TreeLinkNode { TreeLinkNode *left; TreeLinkNode *right; TreeLinkNode *nex ...

随机推荐

  1. 基于NodeJS微信公众号

    最近重新研究了微信公众号的高级接口,原来也利用C#或JAVA写过微信公众号,主要是消息的基础接口. 由于当时不知道微信公众号可以申请测试公众号,微信测试公众号基本上没有任何限制,对于开发来说是一个不错 ...

  2. vs2015 已经支持开发asp .net core 1.0 rc2 程序了

    vs2015 已经支持开发asp .net core 1.0 rc2 程序了 http://mp.weixin.qq.com/s?__biz=MzI0MzM1ODczOQ==&mid=2247 ...

  3. JavaScript学习总结——我所理解的JavaScript闭包

    一.闭包(Closure) 1.1.什么是闭包? 理解闭包概念: a.闭包是指有权限访问另一个函数作用域的变量的函数,创建闭包的常见方式就是在一个函数内部创建另一个函数,也就是创建一个内部函数,创建一 ...

  4. js判断窗体或容器滚动条到底部

    NO1---jquery判断窗体滚动条到底部 $(window).scroll(function () {if ($(window).scrollTop() >= $(document).hei ...

  5. 20个不可思议的 WebGL 示例和演示

    WebGL 是一项在网页浏览器呈现3D画面的技术,有别于过去需要安装浏览器插件,通过 WebGL 的技术,只需要编写网页代码即可实现3D图像的展示.WebGL 可以为 Canvas 提供硬件3D加速渲 ...

  6. JS高程4.变量,作用域和内存问题(2)执行环境及作用域

    1.执行环境:执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为, 每个执行环境都有一个与之相关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中. 2.全局执行环境: 最外围的 ...

  7. 我的屌丝giser成长记-研二篇

    之前有提到过的,本来按照计划中,研一结束就该去深圳中科院研究所实习的,之前跟里面师兄说好了的,奈何导师又接到一个新的科研研究项目,跟学院的几个其他老师一起合作的,主要是关于土地流转系统,而且是一个挺大 ...

  8. android Intent介绍

    Android中提供了Intent机制来协助应用间的交互与通讯,Intent负责对应用中一次操作的动作.动作涉及数据.附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 ...

  9. An App ID with Identifier 'com.XXX.XXX’ is not available. Please enter a different string.报错

    昨天刚刚升的Xcode7.3和iOS9.3,然后没怎么使用这两样就下班了,但是今天早上来了之后,就发现突然之间不能真机测试和运行代码了,一看才发现xcode报错: An App ID with Ide ...

  10. OC字符串基本操作

    不可变的字符串的修改方法有返回值(重新指向新的字符串地址) 可变的字符串的修改方法没有返回值(修改字符串本身) // NSString 不可变字符串 // 1.创建字符串对象 // 使用初始化方法创建 ...