給定一個二叉樹,原地將它展開爲鏈表。
例如,給定二叉樹
1
/ \
2 5
/ \ \
3 4 6
將其展開爲:
1
\
2
\
3
\
4
\
5
\
6
其展開就是一個前序遍歷
可以發現展開的順序其實就是二叉樹的先序遍歷。算法和 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);
}
};
這個是讓遞歸實現了一個一個點的回溯。