Given a binary tree

  1. struct Node {
  2. int val;
  3. Node *left;
  4. Node *right;
  5. Node *next;
  6. }

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:

  1. 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}
  2.  
  3. 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}
  4.  
  5. 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 的延续,原本的完全二叉树的条件不再满足,但是整体的思路还是很相似,仍然有递归和非递归的解法。我们先来看递归的解法,这里由于子树有可能残缺,故需要平行扫描父节点同层的节点,找到他们的左右子节点。代码如下:

解法一:

  1. class Solution {
  2. public:
  3. Node* connect(Node* root) {
  4. if (!root) return NULL;
  5. Node *p = root->next;
  6. while (p) {
  7. if (p->left) {
  8. p = p->left;
  9. break;
  10. }
  11. if (p->right) {
  12. p = p->right;
  13. break;
  14. }
  15. p = p->next;
  16. }
  17. if (root->right) root->right->next = p;
  18. if (root->left) root->left->next = root->right ? root->right : p;
  19. connect(root->right);
  20. connect(root->left);
  21. return root;
  22. }
  23. };

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

解法二:

  1. // Non-recursion, more than constant space
  2. class Solution {
  3. public:
  4. Node* connect(Node* root) {
  5. if (!root) return NULL;
  6. queue<Node*> q;
  7. q.push(root);
  8. while (!q.empty()) {
  9. int len = q.size();
  10. for (int i = ; i < len; ++i) {
  11. Node *t = q.front(); q.pop();
  12. if (i < len - ) t->next = q.front();
  13. if (t->left) q.push(t->left);
  14. if (t->right) q.push(t->right);
  15. }
  16. }
  17. return root;
  18. }
  19. };

虽然以上的两种方法都能通过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之后断开,这样又回到了初始状态,以此往复就可以都连上了,代码如下:

解法三:

  1. // Non-recursion, constant space
  2. class Solution {
  3. public:
  4. Node* connect(Node* root) {
  5. Node *dummy = new Node(, NULL, NULL, NULL), *cur = dummy, *head = root;
  6. while (root) {
  7. if (root->left) {
  8. cur->next = root->left;
  9. cur = cur->next;
  10. }
  11. if (root->right) {
  12. cur->next = root->right;
  13. cur = cur->next;
  14. }
  15. root = root->next;
  16. if (!root) {
  17. cur = dummy;
  18. root = dummy->next;
  19. dummy->next = NULL;
  20. }
  21. }
  22. return head;
  23. }
  24. };

类似题目:

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. 【分布式】Zookeeper在大型分布式系统中的应用

    一.前言 上一篇博文讲解了Zookeeper的典型应用场景,在大数据时代,各种分布式系统层出不穷,其中,有很多系统都直接或间接使用了Zookeeper,用来解决诸如配置管理.分布式通知/协调.集群管理 ...

  2. 如果你也会C#,那不妨了解下F#(4):了解函数及常用函数

    函数式编程其实就是按照数学上的函数运算思想来实现计算机上的运算.虽然我们不需要深入了解数学函数的知识,但应该清楚函数式编程的基础是来自于数学. 例如数学函数\(f(x) = x^2+x\),并没有指定 ...

  3. Rafy 框架 - 流水号插件

    Rafy 框架又添新成员:流水号插件.本文将解释 Rafy 框架中的流水插件的场景.使用方法. 场景 在开发各类数据库应用系统时,往往需要生成从一开始的流水号,有时还需要按月或者按日进行独立生成,如下 ...

  4. MFC AfxMessageBox默认标题修改

    在工程的资源String Table里面添加AFX_IDS_APP_TITLE,然后设置其值即可,AFX_IDS_APP_TITLE的值就是AfxMessageBox的标题

  5. Eclipse 日期和时间格式自定义

    点击下载Eclipse插件  org.eclipse.text_3.5.300.v20130515-1451.jar  覆盖下图所示的jar文件. /************************* ...

  6. LinqToXml (一) Create Xml file By Dom /Linq

    目前,在xml 应用编程领域比较流行的开发模型是W3C 提供的DOM(文档对象模型),在.net Framework 通过命名空间 System.Xml 对该技术提供了支持.随着Linq to XMl ...

  7. ORM是什么?如何理解ORM

    一.ORM简介         对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术.简单的说,ORM是通过使 ...

  8. xcode中的.h和.m文件分别是什么意思?各有什么用?

    .h 表示头文件,用来声明各种成员变量,方法,属性之类的.在import的时候用头文件. .m 主要用来实现.h 里声明的方法.举个例子,如果要写一个方法,你要在.h里先声明: - (void)myM ...

  9. HTML常用标签

    HTML常用标签: HTML文档格式: 首先,HTML是一种超文本标签语言,它是制作网页的基础. 其次,HTML文档中至少包含基本的和成对的<html> </html>.< ...

  10. querySelector系列方法相比 getElementsBy 系列方法有什么区别?

    querySelector 和  querySelectorAll 相比下面这些方法有什么区别? getElementsByTagName getElementsByClassName getElem ...