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


 

Given a binary tree

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.

Initially, all next pointers are set to NULL.

 

Example:

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}

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}

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 的延續,原本的完全二叉樹的條件不再滿足,但是整體的思路還是很相似,仍然有遞歸和非遞歸的解法。我們先來看遞歸的解法,這里由於子樹有可能殘缺,故需要平行掃描父節點同層的節點,找到他們的左右子節點。代碼如下:

 

解法一:

class Solution {
public:
    Node* connect(Node* root) {
        if (!root) return NULL;
        Node *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);
        return root;
    }
};

 

對於非遞歸的方法,我驚喜的發現之前的方法直接就能用,完全不需要做任何修改,算法思路可參見之前的博客 Populating Next Right Pointers in Each Node,代碼如下:

 

解法二:

// Non-recursion, more than constant space
class Solution {
public:
    Node* connect(Node* root) {
        if (!root) return NULL;
        queue<Node*> q;
        q.push(root);
        while (!q.empty()) {
            int len = q.size();
            for (int i = 0; i < len; ++i) {
                Node *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);
            }
        }
        return root;
    }
};

 

雖然以上的兩種方法都能通過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之后斷開,這樣又回到了初始狀態,以此往復就可以都連上了,代碼如下:

 

解法三: 

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

 

類似題目:

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 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM