leetcode116. 填充每个节点的下一个右侧节点指针

每种方法都有详细注解,第三种【使用已建立的next指针】我写了非常详细的题解,俺觉得应该是看完就能懂的。
温馨提示:可以先画个树然后跟着我模拟,应该会非常清晰

法一、递归

时间复杂度O(n),空间复杂度O(logn)

Node* connect(Node* root) {
    if (root == nullptr || root->left == nullptr) return root;
    //当root为叶子结点时root->left不存在,就不需要往下给它们连了
    //连接1、将root的左右子相连
    root->left->next = root->right;
    //连接2、将root的右子与root->next的左子相连
    if (root->next) root->right->next = root->next->left;//只有当root为该层最后一个结点时root->next才==nullptr
    if (root->left) connect(root->left);
    if (root->right) connect(root->right);
}

法二、BFS 层次遍历 + 队列

时间复杂度O(n),空间复杂度O(n)

跟着下面代码模拟…比如当size=que.size()=4时,此时队列中元素为[4,5,6,7],进入内层循环。第一次内层循环进入后size–变为3,p=front=4, 4->next=5, 由于4没有孩子因此直接进入下一循环···直到最后一次内层循环进入后size–变为0,队列元素为[7],p=front=7弹出, 因为size=0遍历到了该层的最后一个结点了,不用再将7与谁连接了。

Node* connect(Node* root) {
    queue<Node*> que;
    if (root != nullptr) que.push(root);
    while (!que.empty()){//外层的while迭代的是层数
        int size = que.size();
        // int upperlevel = size;
        while (size--) {//遍历整层结点
            //取出队首结点--上一层的结点
            Node* p = que.front();
            que.pop();
            //连接
            if (size > 0) p->next = que.front();
            //除了最后一次内层循环,也就是执行完size--后size=0,遍历到上一层的最后一个结点,
            //由于最后一个结点后面没有结点了,因此不需要将最后一个结点与谁连接起来

            //拓展下一层结点
            if (p->left) que.push(p->left);
            if (p->right) que.push(p->right);
        }
    }
}

法三、使用已建立的next指针

时间复杂度O(n),空间复杂度O(1)

一、连接的两种情况
(1)连接同一父节点的两个子节点,它们可以通过该父节点直接连接到一起【cur->left->next = cur->right;】
(2)连接(cur的右子)与(cur->next的左子),可以通过cur与cur->next之间已建立的next指针进行连接.【cur->right->next = cur->next->left;】

简言之,连接涉及两层 => 遍历第i层的结点时给第i+1层的结点做连接:
遍历到第i层的结点cur时,需要
(1)连接cur的左右子结点;
(2)连接cur->right与cur->next->left.
每完成一个cur的连接就要更新cur–右移【cur=cur->next】,直到遍历完第i层的最后一个结点时cur->next==nullptr该层遍历结束,第i+1层的结点之间都已建立好了next。

(但是注意当cur遍历到第i层的最后一个结点时不需要做第二步连接,因为cur->next==nullptr, cur->right已经是第i+1层的最后一个结点)

第i层遍历完成之后要遍历下一层了,也就要从下一层(第i+1层)的第一个结点(leftmost)开始遍历,给第i+2层的结点做连接,那么怎么才能找到下一层的第一个结点呢?
————刚开始第i层遍历前的cur不就是第i层的第一个结点吗?则此时cur的左子就是第i+1层的第一个结点。因此只需要在该层遍历之前保存cur的初始值leftmost,则leftmost->left就是下一层的第一个结点,遍历完该层再将cur更新即可.

Node* connect(Node* root) {
    if (root == nullptr) return root;
    Node* leftmost = root;//leftmost:每一层的最左结点
    Node * cur = root;//用于遍历一层结点
    //直接用root遍历则会改变root
    while (leftmost->left != nullptr) {//外层while迭代的是层数
        //若leftmost->left == nullptr说明leftmostcur是叶子节点,则不需要继续连接了
        leftmost = leftmost->left;//保存下一层的第一个结点
        while (cur) {//内层的while迭代的是层中结点
            //用cur遍历第i层的每一个结点,通过左右指针以及该层已建立的next连接第i+1层的结点
            cur->left->next = cur->right;//连接(1)
            if (cur->next != nullptr) {
                cur->right->next = cur->next->left;//连接(2)
                cur = cur->next;//处理下一个结点
            }
            else break;//直到cur->next==nullptr该层遍历结束
        }
        cur = leftmost;//一层遍历结束,更新cur
    }
    return root;
}

呼,写题解花了我挺长时间的,如果有帮助的话可以评论区告诉我给我激励一下bro~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值