问题描述:
来源:LeetCode第99题
难度:中等
给你二叉搜索树的根节点root,该树中的两个节点的值被错误地交换。请在不改变其 结构的情况下,恢复这棵树。
提示:
- 树上节点的数目在范围
[2, 1000]
内 -231 <= Node.val <= 231 - 1
递归解法:
解这道题我们首先要知道,什么叫二叉搜索树,二叉搜索树指:若它的左子树不空,则左子树上所有结点的值均小于 它的根结点的值;若它的右子树不空,则右子树上所有结点的值均大于它的根结点的 值;它的左、右子树也分别为二叉搜索树。
然后我们还需要知道,树的中序遍历的结果是有序的。知道这个,这道题就简单了。我们对序列做中序遍历,如果每一节点的值大于下一个节点的值,那么说明发生了逆序,且这一个节点位第一个错误节点。接下来找到第二个错误节点。交换两个节点的值就可以了。
代码:
class Solution {
public:
//pre 是指当前节点的前一个节点
TreeNode* pre;
//第一个错误的节点
TreeNode* first;
// 第二个错误的节点
TreeNode* second;
void dfs(TreeNode* root)
{
if(root)
{
dfs(root->left);
// 二叉搜索树的中序遍历是有序的,
// 如果前一个结点的值大于当前节点,且first==NULL 说明此时的
// pre为第一个错误节点
if(first==NULL && pre!=NULL && pre->val>root->val)
{
first=pre;
}
// 若二叉树中序遍历的结果是[1,6,3,4,2,7],很明显是2 和 6发生了交换
// 第一个错误的节点是6>3,而第二个是2<4,所以上面是保留pre ,而下面要把root
// 赋给second
if(first!=NULL && pre->val>root->val)
{
second=root;
}
// 更新pre
pre=root;
dfs(root->right);
}
}
void recoverTree(TreeNode* root) {
dfs(root);
// 交换两个节点的值
swap(first->val,second->val);
}
};
有递归的方法,当也有非递归的方法。
非递归解法:
这题我们只要明白二叉搜索树的中序遍历结果是有序的,那么这道题就很容易解答了。中序遍历可以用递归,也可以不用。下面看看不用递归的中序遍历吧。
模板:
void recoverTree(TreeNode* root) {
// 创建一个栈
stack<TreeNode*> s;
while(root!=NULL || !s.empty())
{
while(root!=NULL)
{
s.push(root);
root=root->left;
}
if(!s.empty())
{
root=s.top();
s.pop();
// 访问节点
root=root->right;
}
}
}
代码:
class Solution {
public:
TreeNode* pre;
TreeNode* first;
TreeNode* second;
void recoverTree(TreeNode* root) {
// 创建一个栈
stack<TreeNode*> s;
while(root!=NULL || !s.empty())
{
while(root!=NULL)
{
s.push(root);
root=root->left;
}
if(!s.empty())
{
root=s.top();
s.pop();
if(first==NULL && pre!=NULL && pre->val>root->val)
{
first=pre;
}
if(first!=NULL && pre->val>root->val)
{
second=root;
}
pre=root;
root=root->right;
}
}
swap(first->val,second->val);
}
};
原理是一样的。