[Leetcode] Populating Next Right Pointers in Each Node II

本文介绍两种填充二叉树next指针的方法:一种是改进后的深度优先搜索(DFS),另一种是宽度优先搜索(BFS)。这两种方法都能在常数额外空间条件下完成任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:


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 I类似,DFS解决。区别在于,需要定义一个函数找到当前root子节点的下一个子节点。方法是从当前root顺着next指针一直找,直到找到一个有子节点的node,返回那个node的子节点。另一个改动是,由于这个函数需要一直顺着next找过去,如果递归的时候先处理左子树,会导致root层的next指针没有处理完全,进而导致无法找到root子节点的下一个子节点。因此,需要先递归右子树,再递归左子树。为什么这样做就可以呢?原因在于,先递归右子树的情况下,root层的next指针依然无法处理完全,但是未处理过的next指针总是在当前root的左边,并不影响寻找下一个子节点。相反,如果先处理左子树,未处理过的next指针总是在当前root的右边,会导致无法找到下一个子节点。第二个问题是,那为什么在Populating Next Right Pointers in Each Node I中可以先处理左子树呢?原因在于对于一个满的树,寻找下一个子节点仅需要当前root的next已经连接即可,并不关心更远处的next是否处理过。但对于一个不满的树,就有可能需要走到很远的地方去寻找下一个子节点。


class Solution {
public:
    TreeLinkNode* next_child_peer(TreeLinkNode* root) {
        if (root == nullptr) return nullptr;
        TreeLinkNode* runner = root->next;
        while (runner != nullptr) {
            if (runner->left != nullptr) return runner->left;
            if (runner->right != nullptr) return runner->right;
            runner = runner->next;
        }
        return nullptr;
    }
    
    void connect(TreeLinkNode *root) {
        if (root == nullptr) return;
        if (root->left != nullptr) {
            if (root->right != nullptr) {
                root->left->next = root->right;
            } else {
                root->left->next = next_child_peer(root);
            }
        }
        if (root->right != nullptr) {
            root->right->next = next_child_peer(root);
        }
        connect(root->right);
        connect(root->left);
    }
};


总结:复杂度为O(2^n). 


思路二:类似的,DFS所用空间为O(h),如果想达到常数空间,需要使用BFS. 方法和 I 类似,只不过下一层的第一个元素不一定是当前层第一个元素的左子节点,在遍历当前层的时候寻找第一个出现的子节点即可。


class Solution {
public:
    TreeLinkNode* next_child_peer(TreeLinkNode* root) {
        if (root == nullptr) return nullptr;
        TreeLinkNode* runner = root->next;
        while (runner != nullptr) {
            if (runner->left != nullptr) return runner->left;
            if (runner->right != nullptr) return runner->right;
            runner = runner->next;
        }
        return nullptr;
    }
    
    void connect(TreeLinkNode *root) {
        if (root == nullptr) return;
        TreeLinkNode* level_head = root;
        while (level_head != nullptr) {
            TreeLinkNode* level_runner = level_head;
            level_head = nullptr;
            while (level_runner != nullptr) {
                if (level_runner->left != nullptr) {
                    if (level_head == nullptr) {   //find the head of the next level
                        level_head = level_runner->left;
                    }
                    if (level_runner->right != nullptr) {
                        level_runner->left->next = level_runner->right;
                    } else {
                        level_runner->left->next = next_child_peer(level_runner);
                    }
                }
                if (level_runner->right != nullptr) {
                    if (level_head == nullptr) {   //find the head of the next level
                        level_head = level_runner->right;
                    }
                    level_runner->right->next = next_child_peer(level_runner);
                }
                level_runner = level_runner->next;
            }
        }
    }
};


总结:复杂度为O(2^n). 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值