https://leetcode.com/problems/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.
这题的测试样例真的很奇怪,而且不管怎么样运行时间都是400+ms,我觉得这是leetcode本身的问题,所以不管他了。
但是这题目本身的做法很有学习的价值。
双队列:
两个队列互相倒来倒去,效率很低(如果使用队列指针应该可以好一点)
/*
// Definition for a Node.
class Node {
public:
int val;
Node* left;
Node* right;
Node* next;
Node() {}
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(root == NULL) return root;
deque<Node*> Q1;
deque<Node*> Q2;
Q1.push_back(root);
Node *pre = NULL;
while(!Q1.empty()){
for(Node *cur : Q1){
if(pre != NULL){
// cout << pre->val << ' ';
pre->next = cur;
}
pre = cur;
if(cur->left != NULL) Q2.push_back(cur->left);
if(cur->right != NULL) Q2.push_back(cur->right);
}
Q1.swap(Q2);
Q2.clear();
pre = NULL;
// cout << endl;
}
return root;
}
};
单队列法:
只使用一个队列,就如同传统的层次遍历,但是问题在于如何在两层之间断开,直观的就是在每一层开始时记录下当前队列的长度,接下来只访问固定长度的队列,剩下的自然就是后面添加进的下一列的结点
/*
// Definition for a Node.
class Node {
public:
int val;
Node* left;
Node* right;
Node* next;
Node() {}
Node(int _val, Node* _left, Node* _right, Node* _next) {
val = _val;
left = _left;
right = _right;
next = _next;
}
};
*/
class Solution {
public:
Node* connect(Node* root) {
static int fast_io = []() { std::ios::sync_with_stdio(false); cin.tie(nullptr); return 0; }();
if(root == NULL) return root;
queue<Node*> Q;
Q.push(root);
while(!Q.empty()){
int len = Q.size();
for(int i = 0; i < len; ++i){
Node *cur = Q.front();
Q.pop();
if(i != len-1) cur->next = Q.front();
if(cur->left) Q.push(cur->left);
if(cur->right) Q.push(cur->right);
}
}
return root;
}
};
逐行遍历法:
针对每一行都利用了上一行已经完成的next指针,利用了二叉树中“一旦某一个结点缺失,其子树结点对应的位置必然也是缺失的”这一特征,保证了正确性。
在每一行结束后需要跳转向下一行的起始时,利用了头结点进行记录。
/*
// Definition for a Node.
class Node {
public:
int val;
Node* left;
Node* right;
Node* next;
Node() {}
Node(int _val, Node* _left, Node* _right, Node* _next) {
val = _val;
left = _left;
right = _right;
next = _next;
}
};
*/
class Solution {
public:
Node* connect(Node* root) {
Node *result = root;
while(root != NULL){
Node *fake_head = new Node(0, NULL, NULL, NULL);
Node *pre = fake_head;
while(root != NULL){
// cout << root->val << ' ';
if(root->left != NULL){
pre->next = root->left;
pre = pre->next;
}
if(root->right != NULL){
pre->next = root->right;
pre = pre->next;
}
root = root->next;
}
root = fake_head->next;
// cout << endl;
}
return result;
}
};