题目
Two elements of a binary search tree (BST) are swapped by mistake.
Recover the tree without changing its structure.
根据上一题的合法性判断,稍作修改,
记录限制元素的位置,可以寻找到不合法的位置,和与之冲突的位置。
根据交换的元素所处的位置,可以分为三种情况:
1、交换的两个位置在一个子树的左右分支上,任何一个元素都不在以另一个元素为根的子树上;
此时交换的这两个位置必然不合法,且是所在分支中不合法位置中深度最小的;
可以首先找到一个不合法的元素。去除以该位置为根的子树后,可找到第二个不合法的元素,交换两者即可。
2、交换的两个位置在一个子树上,一个为该子树的根,另一个在该子树的左子树上;
此时左子树上存在不合法位置,其与发生交换的子树的根冲突;
寻找到第一个不合法位置后,即可找到冲突的位置,即为其中一个交换位置;
另一个元素是第一个交换位置左子树中的最大元素,找到后交换即可;
3、交换的两个位置在一个子树上,一个为该子树的根,另一个在该子树的右子树上;
此时左子树合法,右子树上存在不合法位置,其与发生交换的子树的根冲突;
寻找到第一个不合法位置后,即可找到冲突的位置,即为其中一个交换位置;
另一个元素是第一个交换位置右子树中的最小元素,找到后交换即可;
代码:
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
struct dp //探测用点
{
TreeNode *tn,*min,*max; //当前位置,当前位置的下限所在位置,上限所在位置
dp(TreeNode *t=NULL,TreeNode *mi=NULL,TreeNode *ma=NULL):tn(t),min(mi),max(ma){}
};
dp test(vector<dp> &sdp) //dfs寻找不符合条件的点
{
int min,max;
dp dp1;
while(!sdp.empty()) //dfs
{
dp1=sdp.back();
sdp.pop_back();
min=dp1.min==NULL?INT_MIN:dp1.min->val; //求限制的值
max=dp1.max==NULL?INT_MAX:dp1.max->val;
if(dp1.tn==NULL)
continue;
if(dp1.tn->val<=min||dp1.tn->val>=max) //不符合要求则返回相应信息
{
return dp1;
break;
}
sdp.push_back(dp(dp1.tn->right,dp1.tn->val>min?dp1.tn:dp1.min,dp1.max)); //更新限制
sdp.push_back(dp(dp1.tn->left,dp1.min,dp1.tn->val<max?dp1.tn:dp1.max));
}
return dp();
}
TreeNode* find_min(TreeNode *root,TreeNode *min) //寻找分支中最小值的点
{
if(root!=NULL)
{
if(root->val<min->val)
min=root;
min=find_min(root->left,min);
min=find_min(root->right,min);
}
return min;
}
TreeNode* find_max(TreeNode *root,TreeNode *max) //寻找分支中最大值的点
{
if(root!=NULL)
{
if(root->val>max->val)
max=root;
max=find_max(root->left,max);
max=find_max(root->right,max);
}
return max;
}
void recoverTree(TreeNode *root) {
dp first,second; //记录不符合要求的点的位置
TreeNode *tp;
vector<dp> sdp; //dfs用栈
sdp.push_back(dp(root)); //压入根
first=test(sdp); //探测第一个
if(first.tn==NULL)
return;
second=test(sdp); //探测非第一个外的分支,找第二个
if(second.tn!=NULL) //存在,说明交换的位置在一个子树树的左右子树上,交换回来即可
{
cout<<"c1";
swap(first.tn->val,second.tn->val);
return;
}
sdp.clear(); //否则,说明交换的位置在一个子树上,其中一个交换位置是该子树的根
int min=first.min==NULL?INT_MIN:first.min->val;
int max=first.max==NULL?INT_MAX:first.max->val;
if(first.tn->val<min) //超下界,说明另一个交换的位置在分支的左子树上,寻找分支最小的位置,和冲突位置交换
{
tp=find_min(first.tn,first.tn);
swap(first.min->val,tp->val);
return;
}
if(first.tn->val>max) //超上界,说明另一个交换的位置在分支的右子树上,寻找分支最大的位置,和冲突位置交换
{
tp=find_max(first.tn,first.tn);
swap(first.max->val,tp->val);
return;
}
}
};