題目描述
【leetcode】117. 填充每個節點的下一個右側節點指針 II( Populating Next Right Pointers in Each Node II)
給定一個二叉樹
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每個 next 指針,讓這個指針指向其下一個右側節點。如果找不到下一個右側節點,則將 next 指針設置爲 NULL。
初始狀態下,所有 next 指針都被設置爲 NULL。
進階:
- 你只能使用常量級額外空間。
- 使用遞歸解題也符合要求,本題中遞歸程序佔用的棧空間不算做額外的空間複雜度。
示例:
輸入:root = [1,2,3,4,5,null,7]
輸出:[1,#,2,3,#,4,5,7,#]
解釋:給定二叉樹如圖 A 所示,你的函數應該填充它的每個 next 指針,以指向其下一個右側節點,如圖 B 所示。
提示:
- 樹中的節點數小於 6000
- -100 <= node.val <= 100
第一次解答
思路
這一題顯然使用層次遍歷求解會更簡單,但是通常我們在進行層次遍歷時,每遍歷一層就需要用隊列去存儲下一層的結點,用作下一輪遍歷,顯然不符合進階要求你只能使用常量級額外空間
。那麼我們如何在常數額外空間下進行層次遍歷呢?
本題比較特別,每個結點提供了next成員,從每一次最左邊結點沿着next就可以遍歷完該層。
但next默認爲空,我們怎麼得到設置好了的next呢?可以採用自頂向下的方法。對於根節點,我們很容易將其下一層結點連接好,連接好後,就可以對下一層結點進行遍歷,然後對連接下下層結點…以此類推。
這裏有個細節就是,下一層的開始結點,是下一層最左邊的那個結點。具體見代碼。
test case:
[-1,-7,9,null,null,-1,-7,null,8,-9]
[1,2,3,4,5,null,7]
[1,2,3,4,5,null,6,7,null,null,null,null,8]
代碼:
/*
// Definition for a Node.
class Node {
public:
int val;
Node* left;
Node* right;
Node* next;
Node() : val(0), left(NULL), right(NULL), next(NULL) {}
Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}
Node(int _val, Node* _left, Node* _right, Node* _next)
: val(_val), left(_left), right(_right), next(_next) {}
};
*/
class Solution {
public:
Node* connect(Node* root) {
if(nullptr == root)
return root;
Node* pRoot = root;
while(nullptr != pRoot){
// 拿到這一層的起始結點
Node* pNode = pRoot;
Node* pPre = nullptr;
// 通過next遍歷這一層
// 將這一層的孩子的next都連接起來
while(nullptr != pNode){
if(nullptr != pNode->left){
if(nullptr != pPre)
pPre->next = pNode->left;
pPre = pNode->left;
}
if(nullptr != pNode->right){
if(nullptr != pPre)
pPre->next = pNode->right;
pPre = pNode->right;
}
pNode = pNode->next;
}
// 計算下一層起始結點pRoot
// 下一個pRoot應該是下一層最靠左的結點
while(nullptr != pRoot && nullptr == pRoot->left &&
nullptr == pRoot->right){
pRoot = pRoot->next;
}
if(nullptr != pRoot)
pRoot = pRoot->left == nullptr ? pRoot->right : pRoot->left;
}
return root;
}
};
結果:
第二次解答
思路
看了官方題解,找下一層起始結點的工作,可以放在連接孩子的過程中。
代碼:
/*
// Definition for a Node.
class Node {
public:
int val;
Node* left;
Node* right;
Node* next;
Node() : val(0), left(NULL), right(NULL), next(NULL) {}
Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}
Node(int _val, Node* _left, Node* _right, Node* _next)
: val(_val), left(_left), right(_right), next(_next) {}
};
*/
class Solution {
public:
Node* connect(Node* root) {
if(nullptr == root)
return root;
Node* pRoot = root;
while(nullptr != pRoot){
// 拿到這一層的起始結點
Node* pNode = pRoot;
Node* pPre = nullptr;
pRoot = nullptr;// 置空,由下面找孩子時得到下一層最靠左的結點
// 通過next遍歷這一層
// 將這一層的孩子的next都連接起來
while(nullptr != pNode){
if(nullptr != pNode->left){
if(nullptr != pPre)
pPre->next = pNode->left;
else
pRoot = pNode->left;
pPre = pNode->left;
}
if(nullptr != pNode->right){
if(nullptr != pPre)
pPre->next = pNode->right;
else
pRoot = pNode->right;
pPre = pNode->right;
}
pNode = pNode->next;
}
// 下一個pRoot應該是下一層最靠左的結點
// while(nullptr != pRoot && nullptr == pRoot->left &&
// nullptr == pRoot->right){
// pRoot = pRoot->next;
// }
// if(nullptr != pRoot)
// pRoot = pRoot->left == nullptr ? pRoot->right : pRoot->left;
}
return root;
}
};
結果: