且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

[LeetCode] Populating Next Right Pointers in Each Node 每个节点的右向指针

更新时间:2021-08-08 12:16:06

Given a binary tree

    struct TreeLinkNode {
      TreeLinkNode *left;
      TreeLinkNode *right;
      TreeLinkNode *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.

Note:

  • You may only use constant extra space.
  • You may assume that it is a perfect binary tree (ie, all leaves are at the same level, and every parent has two children).

For example,

Given the following perfect binary tree,

         1
       /  \
      2    3
     / \  / \
    4  5  6  7

After calling your function, the tree should look like:

         1 -> NULL
       /  \
      2 -> 3 -> NULL
     / \  / \
    4->5->6->7 -> NULL

这道题实际上是树的层序遍历的应用,可以参考之前的博客Binary Tree Level Order Traversal 二叉树层序遍历,既然是遍历,就有递归和非递归两种方法,***两种方法都要掌握,都要会写。下面先来看递归的解法,由于是完全二叉树,所以若节点的左子结点存在的话,其右子节点必定存在,所以左子结点的next指针可以直接指向其右子节点,对于其右子节点的处理方法是,判断其父节点的next是否为空,若不为空,则指向其next指针指向的节点的左子结点,若为空则指向NULL,代码如下:

C++ 解法一:

// Recursion, more than constant space
class Solution {
public:
    void connect(TreeLinkNode *root) {
        if (!root) return;
        if (root->left) root->left->next = root->right;
        if (root->right) root->right->next = root->next? root->next->left : NULL;
        connect(root->left);
        connect(root->right);
    }
};

对于非递归的解法要稍微复杂一点,但也不算特别复杂,需要用到queue来辅助,由于是层序遍历,每层的节点都按顺序加入queue中,而每当从queue中取出一个元素时,将其next指针指向queue中下一个节点即可。代码如下:

C++ 解法二:

// Non-recursion, more than constant space
class Solution {
public:
    void connect(TreeLinkNode *root) {
        if (!root) return;
        queue<TreeLinkNode*> q;
        q.push(root);
        q.push(NULL);
        while (true) {
            TreeLinkNode *cur = q.front();
            q.pop();
            if (cur) {
                cur->next = q.front();
                if (cur->left) q.push(cur->left);
                if (cur->right) q.push(cur->right);
            } else {
                if (q.size() == 0 || q.front() == NULL) return;
                q.push(NULL);
            }
        }
    }
};

上面的方法巧妙的通过给queue中添加空指针NULL来达到分层的目的,使每层的最后一个节点的next可以指向NULL,那么我们可以换一种方法来实现分层,我们对于每层的开头元素开始遍历之前,先统计一下该层的总个数,用个for循环,这样for循环结束的时候,我们就知道该层已经被遍历完了,这也是一种好办法:

C++ 解法三:

class Solution {
public:
    void connect(TreeLinkNode *root) {
        if (!root) return;
        queue<TreeLinkNode*> q;
        q.push(root);
        while (!q.empty()) {
            int size = q.size();
            for (int i = 0; i < size; ++i) {
                TreeLinkNode *t = q.front(); q.pop();
                if (i < size - 1) {
                    t->next = q.front();
                }
                if (t->left) q.push(t->left);
                if (t->right) q.push(t->right);
            }
        }
    }
};

上面三种方法虽然叼,但是都不符合题意,题目中要求用O(1)的空间复杂度,所以我们来看下面这种碉堡了的方法。用两个指针start和cur,其中start标记每一层的起始节点,cur用来遍历该层的节点,设计思路之巧妙,不得不服啊:

C++ 解法四:

class Solution {
public:
    void connect(TreeLinkNode *root) {
        if (!root) return;
        TreeLinkNode *start = root, *cur = NULL;
        while (start->left) {
            cur = start;
            while (cur) {
                cur->left->next = cur->right;
                if (cur->next) cur->right->next = cur->next->left;
                cur = cur->next;
            }
            start = start->left;
        }
    }
};

本文转自博客园Grandyang的博客,原文链接:每个节点的右向指针[LeetCode] Populating Next Right Pointers in Each Node ,如需转载请自行联系原博主。