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

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

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

What if the given tree could be any binary tree? Would your previous solution still work?

Note:

  • You may only use constant extra space.

For example,
Given the following binary tree,

         1
       /  \
      2    3
     / \    \
    4   5    7

After calling your function, the tree should look like:

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

這道是之前那道Populating Next Right Pointers in Each Node 每個節點的右向指標的延續,原本的完全二叉樹的條件不再滿足,但是整體的思路還是很相似,仍然有遞迴和非遞迴的解法。我們先來看遞迴的解法,這裡由於子樹有可能殘缺,故需要平行掃描父節點同層的節點,找到他們的左右子節點。程式碼如下:

解法一:

// Recursion, more than constant space
class Solution {
public:
    void connect(TreeLinkNode *root) {
        if (!root) return;
        TreeLinkNode *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); } };

解法二:

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

雖然以上的兩種方法都能通過OJ,但其實它們都不符合題目的要求,題目說只能使用constant space,可是OJ卻沒有寫專門檢測space使用情況的test,那麼下面貼上constant space的解法,這個解法也是用的層序遍歷,只不過沒有使用queue了,我們建立一個dummy結點來指向每層的首結點的前一個結點,然後指標t用來遍歷這一層,我們實際上是遍歷一層,然後連下一層的next,首先從根結點開始,如果左子結點存在,那麼t的next連上左子結點,然後t指向其next指標;如果root的右子結點存在,那麼t的next連上右子結點,然後t指向其next指標。此時root的左右子結點都連上了,此時root向右平移一位,指向其next指標,如果此時root不存在了,說明當前層已經遍歷完了,我們重置t為dummy結點,root此時為dummy->next,即下一層的首結點,然後dummy的next指標清空,或者也可以將t的next指標清空,因為前面已經將t賦值為dummy了。那麼現在想一想,為什麼要清空?因為我們用dummy的目的就是要直到下一行的首結點的位置即dummy->next,而一旦將root賦值為dummy->next了之後,這個dummy的使命就已經完成了,必須要斷開,如果不斷開的話,那麼假設現在root是葉結點了,那麼while迴圈還會執行,不會進入前兩個if,然後root右移賦空之後,會進入最後一個if,之前沒有斷開dummy->next的話,那麼root又指向之前的葉結點了,死迴圈誕生了,跪了。所以一定要記得清空哦,呵呵噠~程式碼如下:

解法三: 

// Non-recursion, constant space
class Solution {
public:
    void connect(TreeLinkNode *root) {
        TreeLinkNode *dummy = new TreeLinkNode(0), *t = dummy;
        while (root) {
            if (root->left) {
                t->next = root->left;
                t = t->next;
            }
            if (root->right) {
                t->next = root->right;
                t = t->next;
            }
            root = root->next;
            if (!root) {
                t = dummy;
                root = dummy->next;
                dummy->next = NULL;
            }
        }
    }
};

類似題目:

參考資料: