0116. Populating Next Right Pointers in Each Node (M)

Populating Next Right Pointers in Each Node (M)

題目

You are given a perfect binary tree where all leaves are on the same level, and every parent has two children. The binary tree has the following definition:javascript

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.html

Initially, all next pointers are set to NULL.java

Example:node

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

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

Note:app

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

題意

對於滿二叉樹的每一層,將當前層每個結點的next域指向該層的右邊一個結點;若是已是當前層的最右結點,則指向null。(限制只能使用\(O(1)\)的額外空間,若是使用遞歸,則系統棧不計入額外空間)this

思路

若是不限制額外空間大小,最簡單的作法是層序遍歷處理。spa

兩種使用遞歸的方法:code

  1. 遞歸參數有兩個,分別是同一層上相鄰的兩個節點A和B,在完成鏈接 \(A.next = B\) 後,它們子樹的鏈接只有三種狀況:\(A.left.next = A.right\)\(A.right.next=B.left\)\(B.left.next=B.right\),因此只要遞歸處理這三種狀況便可。固然這種遞歸方式存在重複鏈接的狀況,由於同一個子樹可能被屢次遞歸訪問。
  2. 遞歸參數只有一個,即當前子樹的根節點x(x與它右邊兄弟結點的鏈接已經處理完畢),若是x存在左子樹,由滿二叉樹的性質,則x必定存在右子樹,同時若是x存在兄弟結點y,則y也必定存在左子樹。將x的左子樹、右子樹和y的左子樹相連,就完成了本層遞歸,接着繼續向x的左右子樹遞歸便可。

另有一種只須要\(O(1)\)空間的迭代方法:
用head指向每一層的最左側結點,用cur從左到右遍歷(經過next鏈接)該層全部結點,在遍歷過程當中將每一個結點的左右子結點與右兄弟結點的左子結點相連。迭代head處理全部層。htm


代碼實現

Java

遞歸1

class Solution {
    public Node connect(Node root) {
        if (root == null) {
            return null;
        }
        
        connect(root.left, root.right);
        return root;
    }

    private void connect(Node x, Node y) {
        if (x == null || y == null) {
            return;
        }

        x.next = y;
        // 分三種狀況處理子樹鏈接
        connect(x.left, x.right);
        connect(x.right, y.left);
        connect(y.left, y.right);
    }
}

遞歸 2

class Solution {
    public Node connect(Node root) {
        rConnect(root);
        return root;
    }

    private void rConnect(Node x) {
        if (x == null) {
            return;
        }

        // 滿二叉樹的性質,若是存在左子樹則必然存在右子樹,且若存在兄弟結點,則兄弟結點也必存在左子樹
        if (x.left != null) {
            x.left.next = x.right;
            if (x.next != null) {
                x.right.next = x.next.left;
            }
        }

        rConnect(x.left);
        rConnect(x.right);
    }
}

層序遍歷(O(1)額外空間)

class Solution {
    public Node connect(Node root) {
        if (root == null) {
            return null;
        }

        Node head = root;
        while (head.left != null) {
            Node cur = head;
            while (cur != null) {
                cur.left.next = cur.right;
                if (cur.next != null) {
                    cur.right.next = cur.next.left;
                }
                cur = cur.next;
            }
            head = head.left;
        }

        return root;
    }
}

層序遍歷(非O(1)額外空間)

class Solution {
    public Node connect(Node root) {
        if (root == null) {
            return null;
        }
        
        Queue<Node> q = new ArrayDeque<>();
        q.offer(root);

        while (!q.isEmpty()) {
            int size = q.size();
            Node[] level = q.toArray(new Node[size]);
            for (int i = 0; i < size; i++) {
                if (i != size - 1) {
                    level[i].next = level[i + 1];
                }
                Node cur = q.poll();
                if (cur.left != null) q.offer(cur.left);
                if (cur.right != null) q.offer(cur.right);
            }
        }
        
        return root;
    }
}

JavaScript

/**
 * @param {Node} root
 * @return {Node}
 */
var connect = function (root) {
  let q = []
  if (root) {
    q.push(root)
  }

  while (q.length) {
    let pre = null
    let size = q.length
    for (let i = 0; i < size; i++) {
      if (i == 0) {
        pre = q.shift()
      } else {
        let cur = q.shift()
        pre.next = cur
        pre = cur
      }
      if (pre.left) q.push(pre.left)
      if (pre.right) q.push(pre.right)
    }
  }
  return root
}

參考blog

cnBlogs - Grandyang

相關文章
相關標籤/搜索