問題:バイナリ検索ツリーの2つのノードが誤って入れ替わっています。
構造を変更せずにこのツリーを復元してください。
例1:
输入: [1,3,null,null,2]
1
/
3
\
2
输出: [3,1,null,null,2]
3
/
1
\
2
例2:
输入: [3,1,4,null,null,2]
3
/ \
1 4
/
2
输出: [2,1,4,null,null,3]
2
/ \
1 4
/
3
上級:
- O(n)空間の複雑さを使用したソリューションは、実装が簡単です。
- 一定のスペースのみを使用するソリューションを考えられますか?
ソース:LeetCode
リンク:https ://leetcode-cn.com/problems/recover-binary-search-tree
著作権はLeetCode が所有しています。商用転載については、正式な許可書にご連絡ください。非商用転載については、出典を明記してください。
基本的な考え方1:順序トラバーサル
二分探索木のインオーダートラバーサルの結果は昇順のシーケンスである必要があるため、この質問のミドルオーダートラバーサルのシーケンスは、2つの要素を交換すると昇順のシーケンスになります。
- まず、二分木の順序通りの探索を実行し、順序通りの探索の結果シーケンスを保存します。
- 結果シーケンスの最初の反転要素の前にある要素preを検索します
- 要素preから後ろに向かって検索します。要素よりも大きい要素tempが見つかった場合、tempの前の要素postは、交換する必要のある要素です。
- 事前と事後の2つの要素を交換する
空間の複雑度はO(n)です。
配列を定義して、順序どおりの走査の順序を保存します
/**
* 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:
vector<TreeNode*> vec;
void recoverTree(TreeNode* root) {
inorder(root);
int pre = 0, i;
for(i = 1; i < vec.size(); ++i){
if(vec[i]->val > vec[pre]->val)
++pre;
else
break;
}
for(; i < vec.size(); ++i){
if(vec[i]->val > vec[pre]-> val)
break;
}
--i;
int t = vec[i]->val;
vec[i]->val = vec[pre]->val;
vec[pre]->val = t;
}
void inorder(TreeNode* root){
if(root == NULL)
return;
inorder(root->left);
vec.push_back(root);
inorder(root->right);
}
};
スペースの複雑さはO(1)です
。2つの変数を定義して、2つのノードを逆の順序で保存します。
/**
* 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 recoverTree(TreeNode* root) {
TreeNode* pre1 = NULL, *pre2 = NULL;
inorder(root, pre1, pre2);
int t = pre1->val;
pre1->val = pre2->val;
pre2->val = t;
}
void inorder(TreeNode* root, TreeNode* &pre1, TreeNode* &pre2){
if(root == NULL)
return;
inorder(root->left, pre1, pre2);
if(pre1 == NULL){
//root是根节点的情况
pre1 = root;
}
else{
if(root->val > pre1->val && (!pre2 || root->val < pre2->val)){
pre1 = root;
}
else if(pre2 == NULL){
//此时找到了第一个需要交换的节点,保存在pre2中
pre2 = pre1;
pre1 = root;
}
if((root->val < pre1->val) && (pre2) && (pre2->val > root->val)){
//此时找到了第二个需要交换的节点保存在pre1中
pre1 = root;
}
}
inorder(root->right, pre1, pre2);
}
};