1. 程式人生 > 實用技巧 >leetcode刷題筆記一百一十六題與一百一十七題 填充每個節點的下一個右側節點指標 與 填充每個節點的下一個右側節點指標 II

leetcode刷題筆記一百一十六題與一百一十七題 填充每個節點的下一個右側節點指標 與 填充每個節點的下一個右側節點指標 II

leetcode刷題筆記一百一十六題與一百一十七題 填充每個節點的下一個右側節點指標 與 填充每個節點的下一個右側節點指標 II

源地址:116. 填充每個節點的下一個右側節點指標

117. 填充每個節點的下一個右側節點指標 II

問題描述:

116題問題描述

給定一個完美二叉樹,其所有葉子節點都在同一層,每個父節點都有兩個子節點。二叉樹定義如下:

struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每個 next 指標,讓這個指標指向其下一個右側節點。如果找不到下一個右側節點,則將 next 指標設定為 NULL。

初始狀態下,所有 next 指標都被設定為 NULL。

輸入:{"$id":"1","left":{"$id":"2","left":{"$id":"3","left":null,"next":null,"right":null,"val":4},"next":null,"right":{"$id":"4","left":null,"next":null,"right":null,"val":5},"val":2},"next":null,"right":{"$id":"5","left":{"$id":"6","left":null,"next":null,"right":null,"val":6},"next":null,"right":{"$id":"7","left":null,"next":null,"right":null,"val":7},"val":3},"val":1}

輸出:{"$id":"1","left":{"$id":"2","left":{"$id":"3","left":null,"next":{"$id":"4","left":null,"next":{"$id":"5","left":null,"next":{"$id":"6","left":null,"next":null,"right":null,"val":7},"right":null,"val":6},"right":null,"val":5},"right":null,"val":4},"next":{"$id":"7","left":{"$ref":"5"},"next":null,"right":{"$ref":"6"},"val":3},"right":{"$ref":"4"},"val":2},"next":null,"right":{"$ref":"7"},"val":1}

解釋:給定二叉樹如圖 A 所示,你的函式應該填充它的每個 next 指標,以指向其下一個右側節點,如圖 B 所示。

117題問題描述

給定一個二叉樹

struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每個 next 指標,讓這個指標指向其下一個右側節點。如果找不到下一個右側節點,則將 next 指標設定為 NULL。

初始狀態下,所有 next 指標都被設定為 NULL。

進階:

你只能使用常量級額外空間。
使用遞迴解題也符合要求,本題中遞迴程式佔用的棧空間不算做額外的空間複雜度。

輸入:root = [1,2,3,4,5,null,7]
輸出:[1,#,2,3,#,4,5,7,#]
解釋:給定二叉樹如圖 A 所示,你的函式應該填充它的每個 next 指標,以指向其下一個右側節點,如圖 B 所示。

提示:

樹中的節點數小於 6000
-100 <= node.val <= 100

/**
* 116題與117題的主要區別在於116題的樹是完美二叉樹,117題的樹是普通二叉樹,處理這類題的思想基本是一致的。1.採用層次遍歷,遍歷過程中修改next指標,或者在上一層遍歷時建立下一層的next指標關係,逐層解決
*/
//基於層次遍歷的解法
/**
 * Definition for a Node.
 * class Node(var _value: Int) {
 *   var value: Int = _value
 *   var left: Node = null
 *   var right: Node = null
 *   var next: Node = null
 * }
 */
import scala.collection.mutable
object Solution {
    def connect(root: Node): Node = {
        if (root == null) return root
        val queue = mutable.Queue[Node]()
        queue.enqueue(root)

        while (queue.isEmpty == false){
            val queueSize = queue.size
            //到本次倒數第二個結點,全部更新next指標
            for (i <- 0 to queueSize-2){
                val currNode = queue.dequeue
                val nextNode = queue.head
                currNode.next = nextNode
                //排除非空的情況
                if (currNode.left != null) queue.enqueue(currNode.left)
                if (currNode.right != null) queue.enqueue(currNode.right)
            }
           
            //更新最後一個結點的next指標與入隊情況
            val floorLastNode = queue.dequeue
            floorLastNode.next = null
            if (floorLastNode.left != null) queue.enqueue(floorLastNode.left)
            if (floorLastNode.right != null) queue.enqueue(floorLastNode.right) 
        }

        return root
    }
}

//使用已建立的 next 指標方法,本質上利用上層遍歷更新下層的next指標
//116題
/**
 * Definition for a Node.
 * class Node(var _value: Int) {
 *   var value: Int = _value
 *   var left: Node = null
 *   var right: Node = null
 *   var next: Node = null
 * }
 */
object Solution {
    def connect(root: Node): Node = {
        if (root == null) return root
        //始終從每層的左側結點開始
        var leftMost = root
        while (leftMost.left != null){
            //使用head遍歷整層結點
            var head = leftMost
            while (head != null){
                //由於是完美二叉樹,head不為空,將左兒子的next指向右兒子
                head.left.next = head.right
                //不同父節點的相鄰節點,將右子樹的next指向存在的兄弟節點的左兒子
                if (head.next != null) head.right.next = head.next.left
                //更新head結點
                head = head.next
            }
            leftMost = leftMost.left
        }
        return root
    }
}

//117題
object Solution {
    def connect(root: Node): Node = {
        var parent = root
        val head = new Node(0)

        while (parent != null){
            //當前層
            var curr = head
            while (parent != null){
                //檢查左子樹情況,有就更新next
                if (parent.left != null){
                    curr.next = parent.left
                    curr = curr.next
                }
                //檢查左子樹情況,有就更新next
                if (parent.right != null){
                    curr.next = parent.right
                    curr = curr.next
                }
                //層內更新
                parent = parent.next 
            }
            //前往下一層
            parent = head.next
            head.next = null
        }
        return root
    }
}