【二叉樹(shù)的屬性】116/117. 填充每個(gè)節(jié)點(diǎn)的下一個(gè)右側(cè)節(jié)點(diǎn)指針I(yè)/II

116.給定一個(gè) 完美二叉樹(shù) ,其所有葉子節(jié)點(diǎn)都在同一層,每個(gè)父節(jié)點(diǎn)都有兩個(gè)子節(jié)點(diǎn)。二叉樹(shù)定義如下:


二叉樹(shù)定義

填充它的每個(gè) next 指針,讓這個(gè)指針指向其下一個(gè)右側(cè)節(jié)點(diǎn)。如果找不到下一個(gè)右側(cè)節(jié)點(diǎn),則將 next 指針設(shè)置為 NULL。
初始狀態(tài)下,所有 next 指針都被設(shè)置為 NULL。


示例

● 進(jìn)階:
你只能使用常量級(jí)額外空間。

使用遞歸解題也符合要求,本題中遞歸程序占用的??臻g不算做額外的空間復(fù)雜度。

解題思路:前序遍歷

按照題意,最先想到的就是層次遍歷。
但是題目要求常量級(jí)空間,而層次遍歷需要借助一個(gè)隊(duì)列。那我們要怎么做呢?來(lái)分析一下。

假設(shè)目前有一個(gè)節(jié)點(diǎn)node(e.g 圖中的2),我們很容易獲得左右孩子節(jié)點(diǎn):node.left(e.g 4)、node.right(e.g 5)
因此,對(duì)于【左孩子→右孩子】(e.g 4→5)來(lái)說(shuō)我們可以很容易辦到,但關(guān)鍵是右孩子如何處理呢?
——觀察不難得知,如果此時(shí)node.next(e.g 3)如果存在,且已經(jīng)連接好了(e.g 2→3),那么我們完全可以借助node找到右孩子連接的那個(gè)節(jié)點(diǎn)(e.g 2→3,3的左孩子為6,實(shí)現(xiàn)5→6)(即通過(guò)上層連接下層)

● 由于處理下一層的時(shí)候,上一層必須處理好,所以我們可以通過(guò)先序遍歷。
可以用迭代法,或者遞歸法。但迭代法需要借助棧,因此本題只能用遞歸法了。

? 注意:遞歸的單層邏輯是 處理當(dāng)前節(jié)點(diǎn)node的左右孩子連接!
(1) 如果當(dāng)前節(jié)點(diǎn)node == null 或者 node.left == null && node.right == null,說(shuō)明無(wú)需連接。
(2) 因?yàn)槭菨M二叉樹(shù),因此,不滿足上述情況,一定同時(shí)存在左右孩子。
(3) 因?yàn)槭菨M二叉樹(shù),如果node.next不存在,說(shuō)明node.right.next一定為null。

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;
    public Node next;

    public Node() {}
    
    public Node(int _val) {
        val = _val;
    }

    public 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 || root.left == null || root.right == null) return root;
        root.left.next = root.right;
        if(root.next != null) root.right.next = root.next.left;
        connect(root.left);
        connect(root.right);
        return root;
    }
}

117.給定一個(gè)二叉樹(shù) 。二叉樹(shù)定義如下:


二叉樹(shù)定義

填充它的每個(gè) next 指針,讓這個(gè)指針指向其下一個(gè)右側(cè)節(jié)點(diǎn)。如果找不到下一個(gè)右側(cè)節(jié)點(diǎn),則將 next 指針設(shè)置為 NULL 。初始狀態(tài)下,所有 next 指針都被設(shè)置為 NULL 。


示例

● 進(jìn)階:
你只能使用常量級(jí)額外空間。

使用遞歸解題也符合要求,本題中遞歸程序占用的??臻g不算做額外的空間復(fù)雜度。

由116題可知,在設(shè)置next的時(shí)候,要利用上層的節(jié)點(diǎn)來(lái)做。我們通過(guò)父節(jié)點(diǎn)來(lái)給孩子節(jié)點(diǎn)的next賦值!?
——因此一個(gè)很重要的點(diǎn)在于!【需要保證上一層的節(jié)點(diǎn)的next已經(jīng)被設(shè)置好了,那么才能進(jìn)行這一層的設(shè)置】?

● 分析:
其實(shí)這道題如果用隊(duì)列來(lái)做非常好做。但是這里咱們追求常量級(jí)空間,因此不使用BFS。
——那么可以使用遞歸去做嗎?答案是不行!因?yàn)?strong>即使是前序遍歷,也不能保證上一層的next被設(shè)置好!

舉例

● 解題思路:模擬 + 設(shè)置三指針
定義三個(gè)指針:
(a) cur:表示當(dāng)層訪問(wèn)的節(jié)點(diǎn)【初始化為root,表示第一層的起始節(jié)點(diǎn)】
(b) preChild:表示前一個(gè)next需要被連接的孩子(下層)節(jié)點(diǎn)【初始化為null】(用于連接)
(c) nextCur:表示下一層的起始節(jié)點(diǎn)【初始化為null】(記錄cur的下一個(gè)值)

● 實(shí)現(xiàn)步驟
假定cur本層及上層節(jié)點(diǎn)的next指針都已經(jīng)設(shè)置好,那么現(xiàn)要設(shè)置cur的下層節(jié)點(diǎn)的next指針:
(a) cur.left != null(如果nextCur == null,則有nextCur = cur.left,這樣可以設(shè)置下一層的起始節(jié)點(diǎn))
說(shuō)明左孩子存在,如果preChild != null,則有:preChild.next = cur.left;此時(shí)重置 preChild = cur.left;
(b) cur.right != null(如果nextCur == null,則有nextCur = cur.right,這樣可以設(shè)置下一層的起始節(jié)點(diǎn))
說(shuō)明有孩子存在,如果preChild != null,則有:preChild.next = cur.right;此時(shí)重置 preChild = cur.right;
(c)cur = cur.next,繼續(xù)從左到右尋找本層的節(jié)點(diǎn),進(jìn)行next的連接。
當(dāng)cur == null 時(shí),說(shuō)明下一層的next已經(jīng)設(shè)置好,如果此時(shí) nextCur != null,那么進(jìn)行下一輪的迭代!
——直到cur == null && nextCur == null,算法結(jié)束。

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;
    public Node next;

    public Node() {}
    
    public Node(int _val) {
        val = _val;
    }

    public 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 null;
        // 基本思路:找完一層,再找一層
        Node preChild = null; // 待連接的孩子節(jié)點(diǎn)
        Node cur = root; // 當(dāng)層的某個(gè)節(jié)點(diǎn)
        Node nextCur = null; // 下一層的起始點(diǎn)
        while(cur != null || nextCur != null){
            if(cur == null){ // 這一層找完了,找下一層
                cur = nextCur;
                nextCur = null;
                preChild = null;
            }
            if(cur.left != null){
                if(nextCur == null) nextCur = cur.left; // 找到下一層的起始點(diǎn)
                if(preChild != null){
                    preChild.next = cur.left; // 將前一個(gè)點(diǎn)連接好
                }
                preChild = cur.left;
            }
            if(cur.right != null){
                if(nextCur == null) nextCur = cur.right;
                if(preChild != null){
                    preChild.next = cur.right; // 將前一個(gè)點(diǎn)連接好
                }
                preChild = cur.right;
            }
            cur = cur.next;
        }
        return root;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容