1. 程式人生 > >[LeetCode] Populating Next Right Pointers in Each Node 每個節點的右向指標

[LeetCode] Populating Next Right Pointers in Each Node 每個節點的右向指標

Given a binary tree

    struct TreeLinkNode {
      TreeLinkNode *left;
      TreeLinkNode *right;
      TreeLinkNode *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

.

Note:

  • You may only use constant extra space.
  • You may assume that it is a perfect binary tree (ie, all leaves are at the same level, and every parent has two children).

For example,
Given the following perfect binary tree,

         1
       /  \
      2    3
     / \  / \
    4  5  6  7

After calling your function, the tree should look like:

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

這道題實際上是樹的層序遍歷的應用,可以參考之前的部落格Binary Tree Level Order Traversal 二叉樹層序遍歷,既然是遍歷,就有遞迴和非遞迴兩種方法,最好兩種方法都要掌握,都要會寫。下面先來看遞迴的解法,由於是完全二叉樹,所以若節點的左子結點存在的話,其右子節點必定存在,所以左子結點的next指標可以直接指向其右子節點,對於其右子節點的處理方法是,判斷其父節點的next是否為空,若不為空,則指向其next指標指向的節點的左子結點,若為空則指向NULL,程式碼如下:

C++ 解法一:

// Recursion, more than constant space
class Solution {
public:
    void connect(TreeLinkNode *root) {
        if (!root) return;
        if (root->left) root->left->next = root->right;
        if (root->right) root->right->next = root->next? root->next->left : NULL;
        connect(root->left);
        connect(root->right);
    }
};

對於非遞迴的解法要稍微複雜一點,但也不算特別複雜,需要用到queue來輔助,由於是層序遍歷,每層的節點都按順序加入queue中,而每當從queue中取出一個元素時,將其next指標指向queue中下一個節點即可。程式碼如下:

C++ 解法二:

// Non-recursion, more than constant space
class Solution {
public:
    void connect(TreeLinkNode *root) {
        if (!root) return;
        queue<TreeLinkNode*> q;
        q.push(root);
        q.push(NULL);
        while (true) {
            TreeLinkNode *cur = q.front();
            q.pop();
            if (cur) {
                cur->next = q.front();
                if (cur->left) q.push(cur->left);
                if (cur->right) q.push(cur->right);
            } else {
                if (q.size() == 0 || q.front() == NULL) return;
                q.push(NULL);
            }
        }
    }
};

上面的方法巧妙的通過給queue中新增空指標NULL來達到分層的目的,使每層的最後一個節點的next可以指向NULL,那麼我們可以換一種方法來實現分層,我們對於每層的開頭元素開始遍歷之前,先統計一下該層的總個數,用個for迴圈,這樣for迴圈結束的時候,我們就知道該層已經被遍歷完了,這也是一種好辦法:

C++ 解法三:

class Solution {
public:
    void connect(TreeLinkNode *root) {
        if (!root) return;
        queue<TreeLinkNode*> q;
        q.push(root);
        while (!q.empty()) {
            int size = q.size();
            for (int i = 0; i < size; ++i) {
                TreeLinkNode *t = q.front(); q.pop();
                if (i < size - 1) {
                    t->next = q.front();
                }
                if (t->left) q.push(t->left);
                if (t->right) q.push(t->right);
            }
        }
    }
};

上面三種方法雖然叼,但是都不符合題意,題目中要求用O(1)的空間複雜度,所以我們來看下面這種碉堡了的方法。用兩個指標start和cur,其中start標記每一層的起始節點,cur用來遍歷該層的節點,設計思路之巧妙,不得不服啊:

C++ 解法四:

class Solution {
public:
    void connect(TreeLinkNode *root) {
        if (!root) return;
        TreeLinkNode *start = root, *cur = NULL;
        while (start->left) {
            cur = start;
            while (cur) {
                cur->left->next = cur->right;
                if (cur->next) cur->right->next = cur->next->left;
                cur = cur->next;
            }
            start = start->left;
        }
    }
};

類似題目:

參考資料: