leetcode 114 二叉樹展開爲鏈表

給定一個二叉樹,原地將它展開爲鏈表。

例如,給定二叉樹

    1
   / \
  2   5
 / \   \
3   4   6
將其展開爲:

1
 \
  2
   \
    3
     \
      4
       \
        5
         \
          6

其展開就是一個前序遍歷

非遞歸寫法:選自:https://leetcode-cn.com/problems/flatten-binary-tree-to-linked-list/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by--26/

可以發現展開的順序其實就是二叉樹的先序遍歷。算法和 94 題中序遍歷的 Morris 算法有些神似,我們需要兩步完成這道題。

將左子樹插入到右子樹的地方
將原來的右子樹接到左子樹的最右邊節點
考慮新的右子樹的根節點,一直重複上邊的過程,直到新的右子樹爲 null
可以看圖理解下這個過程。

可以看圖理解下這個過程。
    1
   / \
  2   5
 / \   \
3   4   6

//將 1 的左子樹插入到右子樹的地方
    1
     \
      2         5
     / \         \
    3   4         6        
//將原來的右子樹接到左子樹的最右邊節點
    1
     \
      2          
     / \          
    3   4  
         \
          5
           \
            6
            
 //將 2 的左子樹插入到右子樹的地方
    1
     \
      2          
       \          
        3       4  
                 \
                  5
                   \
                    6   
        
 //將原來的右子樹接到左子樹的最右邊節點
    1
     \
      2          
       \          
        3      
         \
          4  
           \
            5
             \
              6         
  

代碼如下:

/**

 * Definition for a binary tree node.

 * 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)//一直以右子樹節點爲root

{

    if(root->left==NULL)root=root->right;//如果當前的左子樹爲空,則

    else

    {

        //找到左子樹最右邊的節點

TreeNode *pre=root->left;

while(pre->right!=NULL)

{

    pre=pre->right;

}

//將原來的右子樹接到左子樹的最右邊節點

            pre->right = root->right;//這個的意思將root->right賦值個pre->right.所以是將pre->right指向根節點的右子樹

 //將左子樹插入到右子樹的地方

            root->right = root->left;

            root->left = NULL;

           // 考慮下一個節點

            root = root->right;//即考慮下一個節點,即上面的圖中將234這個

    }

}

    }

};

題目要求原地展開爲鏈表。原地的意思,一個是展開的結果,反應在傳入參數,另一個是不能使用容器。in-place 的意思可能更多說的是直接在原來的節點上改變指向,空間複雜度並沒有要求。所以這道題也可以用遞歸解一下。

所以前序遍歷標準套路,使用棧、隊列存儲節點的方案,就不符合題目要求了。

對於每個點來說,將其左邊的left置爲NULL,而將左邊的插入到節點的右邊、

遞歸是一步一步向下的,而且是每個點都是一個重複,所以只需要考慮根節點的情況,根據例子,將節點的左邊轉爲鏈表,右邊也轉爲鏈表,然後讓左邊的鏈表的表尾接上右邊鏈表的表頭,以根節點爲討論的對象,然後將根節點的的left放到right的下邊,然後將根節點的left置爲NULL,其他點也是重複這個動作.

代碼如下:

/**

 * Definition for a binary tree node.

 * 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)return;

flatten(root->left);

TreeNode*temp=root->right;//記錄當前節點的右子樹

root->right=root->left;//將當前節點的right指向當前節點的left。如果沒有上一步的TreeNode*temp=root->right;就會讓當前節點原先的右子樹節點丟失

root->left=nullptr;

while(root->right){root=root->right;}//這個是一直向後走的,此時的root->right實際上是原先的root->left。即root-、、     //>right=root->left;這一句,這句的意思是找到左子樹的最右邊節點。

flatten(root->right);//這個放在flatten(root->left);之後或者這兒都是可以的,因爲上面的root->right=root->left;所以這個是將上面的中的2,3,4結構展開。

root->right=temp;//這個是將左子樹的最右邊節點指向根節點右子樹

  }

};

 

 

class Solution {

public:

    void flatten(TreeNode* root) {

if(!root)return;

flatten(root->left);

TreeNode*pre=root->right;

root->right=root->left;

root->left=nullptr;

while(root->right)root=root->right;//

root->right=pre;

flatten(root->right);

    }

};

這個是讓遞歸實現了一個一個點的回溯。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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