leetcode----------填充每个节点的下一个右侧节点指针

给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。

初始状态下,所有 next 指针都被设置为 NULL。

 

进阶:

你只能使用常量级额外空间。
使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。

解题思路:

关键的地方就是左子树怎么连接到右子树;我刚开始只想到层次遍历的话,我可以直接一直连到最后,直接保证了同一层的左子树和右子树连在一起,这样会简单很多。但是需要额外辅助空间:O(n);并且,我还需要判断这一层的末尾,刚开始我没想到好的办法,因为这是一个完全二叉树,那么每一层都是2的n次方,因此,只要每一次遍历计数,只要够数了,就指向空;

class Solution {
public:
    Node* connect(Node* root) {
        if(!root)
            return NULL;
        queue<Node*> node;
        queue<Node*> level;
        node.push(root);
        while(!node.empty())
        {
            Node* temp = node.front();
            node.pop();
            level.push(temp);
            if(temp->left)
                node.push(temp->left);
            if(temp->right)
                node.push(temp->right);
        }
        Node * top =level.back();
        top->next=NULL;
        Node* old=level.front();
        level.pop();
        int i=0;
        int num=1;
        while(!level.empty())
        {
            if(old){
                Node* temp =level.front();
                if(num==pow(2,i))
                {
                    i++;
                    old->next=NULL;
                    num=0;
                    old=NULL;
                    continue;
                }   
                old->next=temp;
            }   
            old = level.front();
            num++;
            level.pop();
        }
        return root;
    }
};

上面这样做的话,辅助空间就是比O(n)还O(n);看了别人的解答,觉得很好:

这里对于每一层都是有一个size的,那么直接在开始的时候记录这个size,每次只遍历这个size的尺寸即可;从而就是i = 0;i < size - 1;假设一层只有4个,那么只要互相连接前3个即可,最后一个就是空,不需要care

class Solution {
public:
    Node* connect(Node* root) {
        if (root == nullptr) {
            return root;
        }
        
        // 初始化队列同时将第一层节点加入队列中,即根节点
        queue<Node*> Q;
        Q.push(root);
        
        // 外层的 while 循环迭代的是层数
        while (!Q.empty()) {
            
            // 记录当前队列大小
            int size = Q.size();
            
            // 遍历这一层的所有节点
            for(int i = 0; i < size; i++) {
                
                // 从队首取出元素
                Node* node = Q.front();
                Q.pop();
                
                // 连接
                if (i < size - 1) {
                    node->next = Q.front();
                }
                
                // 拓展下一层节点
                if (node->left != nullptr) {
                    Q.push(node->left);
                }
                if (node->right != nullptr) {
                    Q.push(node->right);
                }
            }
        }
        
        // 返回根节点
        return root;
    }
};

解答中给了提示,可以使用递归,那么就化成每一次需要做同样的事;可以从图中看到,如果上一层连接了左右,那么在连接一个root的节点的左右节点的时候,接下来对于root右节点需要连接另一颗右子树的左节点,那么就可以判断root有没有连接next节点,如果连接了那么关系就是 root.right.next = root.next.left;因为是递归,那么只要保证上一层root的next肯定是连接的就可以了

class Solution {
public:
    Node* connect(Node* root) {
        if (root == nullptr) {
            return root;
        }
        
        // 从根节点开始
        Node* leftmost = root;
        
        while (leftmost->left != nullptr) {
            
            // 遍历这一层节点组织成的链表,为下一层的节点更新 next 指针
            Node* head = leftmost;  //这个记录这一层最左节点很重要
            
            while (head != nullptr) {
                
                // CONNECTION 1
                head->left->next = head->right;
                
                // CONNECTION 2
                if (head->next != nullptr) {
                    head->right->next = head->next->left;
                }
                
                // 指针向后移动
                head = head->next;
            }
            
            // 去下一层的最左的节点
            leftmost = leftmost->left;
        }
        
        return root;
    }
};

 

而递归的解法就是,深度搜索最左节点,每一次都是连接root的左到右;然后递归root的右节点(这次的递归是保证跨着连,并且之前的左右连,已经保证了root的next是连好的),如果root的next不为空,那么就利用这个公式root.right.next = root.next.left

public Node connect(Node root) {
        dfs(root, null);
        return root;
    }

    private void dfs(Node curr, Node next) {
        if (curr == null)
            return;
        curr.next = next;
        dfs(curr.left, curr.right);
        dfs(curr.right, curr.next == null ? null : curr.next.left);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值