題目原文: Two elements of a binary search tree (BST) are swapped by
mistake.
Recover the tree without changing its structure
題意解釋
- 大家都知道,二叉排序樹BST的中序序列是由小到大排序的,而如果BST的兩個節點交換後,其中序遍歷序列一定不再是由小到大排序的。
例如原來二叉樹是 “214##35”,交換節點2和3之後變成了314##25,如下圖所示:
交換前:(中序遍歷序列:12345)
交換後:(中序遍歷序列:13245)
思路
用中序遍歷序列的遞歸方法可以解決該問題,我們先寫一個簡單的中序遍歷的遞歸代碼:
void traverse(TreeNode *root){
if(root == NULL)
return ;
traverse(root->left);
//Do something
traverse(root->right);
}
在 Do something 部分可以完成諸如輸出,入棧等操作。那麼對於這道題目來說,我們在Do something部分將要完成的工作是找到 fristElement
和secondElement
,即第一個逆序的節點和第二個逆序的節點。
中序遍歷序列是13245
我們比較每個節點與其中序遍歷的下一個節點,我們可以發現,3是第一個要交換的節點firstElement
,因爲3應該小於後一個節點,而2是第二個要交換的節點secondElement
,因爲2應該大於前一個節點。
我們定義的前一個節點和後一個節點是按照中序遍歷序列定義的。
我們定義三個變量firstElement
,secondElement
,preElement
,分別存儲要交換的兩個節點和當前遍歷到的節點的中序前驅。
代碼如下(請注意註釋部分)
class Solution{
public:
//firstElement和secondElement分別代表第一個逆序的位置和第二個逆序的位置
//第一步需要在中序遍歷序列中找到這兩個位置,第二步需要交換這兩個位置
TreeNode *firstElement;
TreeNode *secondElement;
TreeNode *preElement; //代表當前遍歷的位置的中序前驅節點,先賦一個最小值
//traverse函數負責找到兩個逆序的位置,隨後用swap函數將這兩個位置進行交換
void recoverTree(TreeNode* root) {
traverse(root);
swap(firstElement->val, secondElement->val);
}
//中序遍歷序列找到兩個逆序的位置
void traverse(TreeNode *root){
if(root == NULL)
return ;
//中序遍歷左子樹
traverse(root->left);
if(preElement != NULL){
//查看是否逆序,如果逆序,給firstElement和secondElement賦值
if(firstElement == NULL && preElement->val > root->val){
//當firstElement還沒有被賦值,第一個逆序位置是pre節點
firstElement = preElement;
}
if(firstElement != NULL && preElement->val > root->val){
//當firstElement已經被賦值,第二個逆序位置是root節點
secondElement = root;
}
}
preElement = root; //更新preElement的值
//中序遍歷右子樹
traverse(root->right);
}
};