原文:117. 填充每个节点的下一个右侧节点指针 II(leetcode 解题) - 每天一个JavaScript小知识@Js中文网 · 码农进阶题库

原文地址:https://www.javascriptc.com/interview-tips/zh_cn/leetcode/leetcode-javascript-solution-0117/

题目:

难度:Middle

相关话题:深度优先搜索

给定一个二叉树

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

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL

初始状态下,所有next 指针都被设置为 NULL

示例:

输入:{"$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}

输出:{"$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}

解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。

提示:

  • 你只能使用常量级额外空间。

  • 使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。


思路:

  • BFS

对于每个root,通过root.next来不断定义它的子树的next,直到root==null,并且通过变量head保存当前root的第一个子树(左优先),当root==null的时候,设置root=head,从而跳转到它的第一个子树,继续定义这个子树的子树的next

var connect = function(root) {
  if(!root)return null
  let cur=root,
      pre=null,
      head=null
  while(cur!=null){
    while(cur!=null){

      if(cur.left){
        if(pre)pre.next=cur.left
        if(!head)head=cur.left
        pre=cur.left
      }

      if(cur.right){
        if(!head)head=cur.right
        if(pre)pre.next=cur.right
        pre=cur.right
      }
      cur=cur.next
    }
    cur=head
    head=null
    pre=null
  }
  return root
};
  • DFS

思想和BFS差不多,对于当前root,通过root.next,定义它的子树的next,注意的是,在递归的时候,需要先递归root.right,这时因为不像BFS是一层一层遍历,DFS是先递归到最底端,然后再返回,而findNext是找出节点的最左的子节点;

如果先root.left,那么最底端一些节点就无法通过next跳转到它的右侧的节点,因为findNext可能找到了最左的子节点,但没有找到更右边的子节点,因此右边的一些节点可能是还未被连接的。

例如:这里由于56无法相连,导致78无法相连。

       1  ->   2
     /  \     / \
    3 -> 4 ->5   6
   /              \
 7                 8

因此,先递归root.right,确保右边都已经连接完毕,再执行root.left

/**
 * @来源: Javascript中文网 - 前端进阶资源教程 https://www.javascriptc.com/
 * @介绍:一个致力于帮助开发者用代码改变世界为使命的平台,每天都可以在这里找到技术世界的头条内容
 * // Definition for a Node.
 * function Node(val,left,right,next) {
 *    this.val = val;
 *    this.left = left;
 *    this.right = right;
 *    this.next = next;
 * };
 */
/**
 * @param {Node} root
 * @return {Node}
 */
var connect = function(root) {
  if(!root)return null
  // BFS
//   let cur=root,
//       pre=null,
//       head=null
//   while(cur!=null){
//     while(cur!=null){

//       if(cur.left){
//         if(pre)pre.next=cur.left
//         if(!head)head=cur.left
//         pre=cur.left
//       }

//       if(cur.right){
//         if(!head)head=cur.right
//         if(pre)pre.next=cur.right
//         pre=cur.right
//       }
//       cur=cur.next
//     }
//     cur=head
//     head=null
//     pre=null
//   }
//   return root
  // DFS
  makeConnect(root)
  return root
  function findNext(node){
    if(!node)return null
    if(node.left)return node.left
    if(node.right)return node.right
    return findNext(node.next)
  }
  function makeConnect(node){
    if(!node)return
    if(node.left && node.right){
      node.left.next=node.right
      node.right.next=findNext(node.next)
    }else if(node.left){
      node.left.next=findNext(node.next)
    }else if(node.right){
      node.right.next=findNext(node.next)
    }

    makeConnect(node.right)
    makeConnect(node.left)
  }
};