[LeetCode]1028. 從先序遍歷還原二叉樹

題目

我們從二叉樹的根節點 root 開始進行深度優先搜索。

在遍歷中的每個節點處,我們輸出 D 條短劃線(其中 D 是該節點的深度),然後輸出該節點的值。(如果節點的深度爲 D,則其直接子節點的深度爲 D + 1。根節點的深度爲 0)。

如果節點只有一個子節點,那麼保證該子節點爲左子節點。

給出遍歷輸出 S,還原樹並返回其根節點 root

示例 1:
在這裏插入圖片描述

輸入:"1-2--3--4-5--6--7"
輸出:[1,2,5,3,4,6,7]

示例 2:
在這裏插入圖片描述

輸入:"1-2--3---4-5--6---7"
輸出:[1,2,5,3,null,6,null,4,null,7]

示例 3:
在這裏插入圖片描述

輸入:"1-401--349---90--88"
輸出:[1,401,null,349,88,90]

提示:

  • 原始樹中的節點數介於 11000 之間。
  • 每個節點的值介於 110 ^ 9 之間。

解題思路

記當前節點爲 T,上一個節點爲 S,那麼實際上只有兩種情況:
1)T 是 S 的左子節點;
2)T 是根節點到 S 這一條路徑上(不包括 S)某一個節點的右子節點。
爲什麼不包括 S?因爲題目中規定了如果節點只有一個子節點,那麼保證該子節點爲左子節點。在 T 出現之前,S 仍然還是一個葉節點,沒有左子節點,因此 T 如果是 S 的子節點,一定是優先變成 S 的左子節點。

對於在先序遍歷中任意的兩個相鄰的節點 S 和 T,要麼 T 是 S 的左子節點(對應上面的第一種情況),要麼在遍歷到 S 之後發現 S 是個葉節點,於是回溯到之前的某個節點,並開始遞歸地遍歷其右子節點(對應上面的第二種情況)。

當得到當前節點的值以及深度信息之後,可以發現:如果 T 是 S 的左子節點,那麼 T 的深度恰好比 S 的深度大 1;在其它的情況下,T 是棧中某個節點(不包括 S)的右子節點,那麼我們將棧頂的節點不斷地出棧,直到 T 的深度恰好比棧頂節點的深度大 1,此時我們就找到了 T 的父節點。

複雜度分析:
時間複雜度:O(|s|),其中 |s| 是字符串 S 的長度。我們的算法不斷地從 S 中取出一個節點的信息,直到取完爲止。在這個過程中,我們實際上是對 S 進行了一次遍歷。
時間複雜度:O(h),其中 h 是還原出的二叉樹的高度。除了作爲答案返回的二叉樹使用的空間以外,我們使用了一個棧幫助我們進行迭代。由於棧中存放了從根節點到當前節點這一路徑上的所有節點,因此最多會有 h 個節點。

代碼

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode recoverFromPreorder(String S) {
        Deque<TreeNode> stack = new LinkedList<>();
        int i = 0;
        while(i<S.length()){
            int level = 0;
            // 如果遇見的是字符 ‘-’,繼續向後遍歷
            while(S.charAt(i) == '-'){
                i++; // 字符索引
                level++; // 節點深度
            }
            int value = 0;
            // 如果是數字
            while(i<S.length() && Character.isDigit(S.charAt(i))){
                value = value*10 + S.charAt(i) - '0';
                i++;
            }
            TreeNode cur = new TreeNode(value);
            // 如果當前深度等於棧的深度且棧非空,表示當前節點是棧頂節點的左孩子
            if(level == stack.size()){
                // 根節點沒有父節點,要進行一次非空的判斷
                if(!stack.isEmpty()){
                    TreeNode node = stack.peek();
                    node.left = cur;
                }
                // TreeNode node = stack.peek();
                // node.left = cur;
            }else{
                while(level != stack.size()){
                    stack.pop();
                }
                TreeNode node = stack.peek();
                node.right = cur;
            }
            stack.push(cur);
        }
        while(stack.size()>1){
            stack.pop();
        }
        TreeNode root = stack.peek();
        return root;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章