1. 程式人生 > >[LeetCode] Add One Row to Tree 二叉樹中增加一行

[LeetCode] Add One Row to Tree 二叉樹中增加一行

Given the root of a binary tree, then value v and depth d, you need to add a row of nodes with value v at the given depth d. The root node is at depth 1.

The adding rule is: given a positive integer depth d, for each NOT null tree nodes N in depth d-1, create two tree nodes with value v as N's left subtree root and right subtree root. And N's

 original left subtree should be the left subtree of the new left subtree root, its original right subtree should be the right subtree of the new right subtree root. If depth d is 1 that means there is no depth d-1 at all, then create a tree node with value v as the new root of the whole original tree, and the original tree is the new root's left subtree.

Example 1:

Input: 
A binary tree as following:
       4
     /   \
    2     6
   / \   / 
  3   1 5   

v = 1

d = 2

Output: 
       4
      / \
     1   1
    /     \
   2       6
  / \     / 
 3   1   5   

Example 2:

Input: 
A binary tree as following:
      4
     /   
    2    
   / \   
  3   1    

v = 1

d = 3

Output: 
      4
     /   
    2
   / \    
  1   1
 /     \  
3       1

Note:

  1. The given d is in range [1, maximum depth of the given tree + 1].
  2. The given binary tree has at least one tree node.

這道題讓我們給二叉樹增加一行,給了我們需要增加的值,還有需要增加的位置深度,題目中給的例子也比較能清晰的說明問題。但是漏了一種情況,那就是當d=1時,這該怎麼加?這時候就需要替換根結點了。其他情況的處理方法都一樣,這裡博主第一映像覺得應該用層序遍歷來做,沒遍歷完一層,d自減1,我們探測,當d==1時,那麼我們需要對於當前層的每一個結點,首先用臨時變數儲存其原有的左右子結點,然後新建值為v的左右子結點,將原有的左子結點連到新建的左子結點的左子結點上,將原有的右子結點連到新建的右子結點的右子結點,是不是很繞-.-|||。如果d不為1,那麼就是層序遍歷原有的排入佇列操作,記得當檢測到d為0時,直接返回,因為新增操作已經完成,沒有必要遍歷完剩下的結點,參見程式碼如下:

解法一:

class Solution {
public:
    TreeNode* addOneRow(TreeNode* root, int v, int d) {
        if (!root) return NULL;
        if (d == 1) {
            TreeNode *newRoot = new TreeNode(v);
            newRoot->left = root;
            return newRoot;
        }
        queue<TreeNode*> q{{root}};
        while (!q.empty()) {
            if (--d == 0) return root;
            int n = q.size();
            for (int i = 0; i < n; ++i) {
                auto t = q.front(); q.pop();
                if (d == 1) {
                    TreeNode *left = t->left;
                    TreeNode *right = t->right;
                    t->left = new TreeNode(v);
                    t->right = new TreeNode(v);
                    t->left->left = left;
                    t->right->right = right;
                } else {
                    if (t->left) q.push(t->left);
                    if (t->right) q.push(t->right);
                }
            }
        }
        return root;
    }
};

雖然博主一貫的理念是二叉樹問題肯定首選遞迴來解,但是這道題博主剛開始以為遞迴沒法解,結果看了大神們的帖子,才發現自己還是圖樣圖森破,難道二叉樹的問題皆可遞迴?反正這道題是可以的,而且寫法so簡潔,乍一看上去,會有疑問,題目中明明d的範圍是從1開始的,為何要考慮d為0的情況,後來讀懂了整個解法後,才為原作者的聰慧歎服。這裡d的0和1,其實相當於一種flag,如果d為1的話,那麼將root連到新建的結點的左子結點上;反之如果d為0,那麼將root連到新建的結點的右子結點上,然後返回新建的結點。如果root存在且d大於1的話,那麼對root的左子結點呼叫遞迴函式,注意此時若d的值正好為2,那麼我們就不能直接減1,而是根據左右子結點的情況分別賦值1和0,這樣才能起到flag的作用嘛,叼的飛起,參見程式碼如下:

解法二:

class Solution {
public:
    TreeNode* addOneRow(TreeNode* root, int v, int d) {
        if (d == 0 || d == 1) {
            TreeNode *newRoot = new TreeNode(v);
            (d ? newRoot->left : newRoot->right) = root;
            return newRoot;
        }
        if (root && d > 1) {
            root->left = addOneRow(root->left, v, d > 2 ? d - 1 : 1);
            root->right = addOneRow(root->right, v, d > 2 ? d - 1 : 0);
        }
        return root;
    }
};

參考資料: