[C++]LeetCode: 102 Flatten Binary Tree to Linked List (二叉樹轉前序鏈表)

題目:

Given a binary tree, flatten it to a linked list in-place.

For example,
Given

         1
        / \
       2   5
      / \   \
     3   4   6

The flattened tree should look like:
   1
    \
     2
      \
       3
        \
         4
          \
           5
            \
             6

click to show hints.

Hints:

If you notice carefully in the flattened tree, each node's right child points to the next node of a pre-order traversal.

Answer 1: 遞歸法

思路:觀察題目轉換的過程,我們按照前序遍歷的順序連接成一個鏈表,不過鏈表還是用樹的結構,就是一直往右走(沒有做孩子)來模擬鏈表。爲了保證節點之間的鏈接,我們維護先序遍歷的前一個節點pre, 然後每次把pre的左結點置空,右結點設爲當前節點(即按照先序遍歷順序)。這裏我們需要注意,還需維護右孩子節點savedRight,以方便等會進行遞歸。否則有可能當前節點的右結點可能被覆蓋,後面就取不到了。

樹的遞歸方法,我們主要就是考慮好遞歸結束條件和遞歸條件,如果遞歸會對樹的結構進行修改的話,我們就需要保存一下結點。

Attention:

1. 維護兩個節點,一個先序遍歷前一個節點pre, 一個當前節點的右孩子節點savedRight。方便鏈接和保護右孩子節點。

private:
    TreeNode* pre = NULL;   //維護一個上次訪問的結點,需要將這次的結點連到pre上
 TreeNode* savedRight = root->right;
2. 注意鏈接過程,我們是把pre的左孩子置空,右孩子設爲當前結點,實現前序鏈表鏈接。

if(pre != NULL)
        {
            pre->left = NULL; //上次結點左子樹置爲空
            pre->right = root; //上次遍歷結點右結點爲root
        }

3. 注意前序遍歷順序,先是root->left遞歸,接下來是維護的右結點遞歸savedRight. 始終維護pre。

 pre = root;
 flatten(root->left);
 flatten(savedRight); //改變了樹的結構,從保存的樹的根右結點繼續遍歷
複雜度:O(N)
AC Code:

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void flatten(TreeNode *root) {
        if(root == NULL) return;
        TreeNode* savedRight = root->right;
        
        if(pre != NULL)
        {
            pre->left = NULL; //上次結點左子樹置爲空
            pre->right = root; //上次遍歷結點右結點爲root
        }
        pre = root;
        flatten(root->left);
        flatten(savedRight); //改變了樹的結構,從保存的樹的根右結點繼續遍歷
    }

private:
    TreeNode* pre = NULL;   //維護一個上次訪問的結點,需要將這次的結點連到pre上
};

Answer 2: 非遞歸方法

思路:

[解題思路]

         1
          \
2
/ \
3 4
\ 5 \ 6

對root的左子樹進行處理,將左子樹的根結點和左子樹的右子樹插入右子樹中。接下來再對結點2進行處理,同樣將2的左子樹插入右子樹中。我們通過訪問結點2(根節點的左孩子)的最右結點(左子樹最上一層的最右結點,最後被訪問),得到了先序遍歷左子樹的最後一個節點(節點4),插入到根結點的右孩子(結點5)的前一個節點(節點4)。不斷進行這個插入過程。

Attention:

1. 找到右子樹的前一個節點,就是根結點的左孩子的最右結點。

TreeNode* ptr = root->left;
while(ptr->right) ptr = ptr->right;
2. 注意如何插入的過程。結合圖記憶

ptr->right = root->right;
root->right = root->left;
root->left = NULL;
3. 置root爲root的右孩子,繼續插入過程,知道root爲NULL, 即root遍歷到樹的最後一個節點。

AC Code:

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void flatten(TreeNode *root) {
        while(root)
        {
            if(root->left)
            {
                TreeNode* ptr = root->left;
                while(ptr->right) ptr = ptr->right;
                ptr->right = root->right;
                root->right = root->left;
                root->left = NULL;
            }
            root = root->right;
        }
    }
};




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章