恢复二叉搜索树问题

问题描述:

来源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);

    }
};

原理是一样的。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

别抢我的辣条~

老板大气!祝老板身体健康!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值