【NewCode-LeetCode】recover-binary-search-tree

传送门

题目

二叉搜索树(BST)中的两个节点被错误地交换了,需要在不改变树的结构的情况下恢复这棵树。

思路

一开始理解错了,以为是两个同一层的节点被交换了,后来发现是我想简单了,题意指的是任意的两个节点;那么如何找到这两个节点呢?

由二叉搜索树的概念,我们知道左子树所有节点的值都小于根节点的值,右子树所有节点的值都大于根节点的值,因此这两个被交换的节点一共有3种可能情况:(此处的根节点是指其中某个子树的根节点,并不一定是root节点)
①一个是左子树中的节点,一个是右子树中的节点
②一个是左子树中的节点,一个是根节点
③一个是根节点,一个是右子树中的节点

首先我们从root根节点开始,然后在它的左子树中找是否存在比它的值大的节点,注意可能有多个节点,但我们要找的是值最大的节点(因为如果找的是次大值的话,仍然不满足二叉搜索树的概念);在右子树中找是否比它的值小的节点,同样找值最小的节点;如果没有,则说明这两个节点在左子树或右子树中,因此递归它的左子树和右子树,然后不断递归,直到找到为止。

如果说的还不是很明白的话,可以对照下面的栗子来分析:
在这里插入图片描述
由图我们可以知道节点3和节点4被错误的交换了,但这是我们肉眼观查出来的,下面我们一步一步分析:
首先从根节点5出发,使用队列判断左子树中不存在大于5的节点,而右子树中也不存在小于5的节点;接着我们判断以2为根节点的子树,可以得知它的左子树和右子树也满足二叉搜索树的条件;然后我们判断以1为根节点的子树,我发现它下面没有子树了,因此返回;然后判断2的右子树,即以3为根节点的子树,这时我们发现它的左子树的值4就大于了根节点3的值,而3的右子树为空,因此最终得出了是3和4这两个节点被错误的交换了,然后使用swap将两个val值交换过来就可以了。

如果觉得还不是很清楚的话,可以多举几个其他情况的栗子分析分析。

代码

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    
    void recoverTree(TreeNode *root) {
        if(!root) return;
        if(!root->left && !root->right) return;
        TreeNode* first=nullptr;
        TreeNode* second=nullptr;
        int flag1 = 0,flag2 = 0;
        int value = root->val;
        queue<TreeNode*> q;
        //以当前节点为根节点,找左数中是否存在比它的val大的节点,且是最大
        if(root->left){
            q.push(root->left);
            int max = value;
            while(!q.empty()){
                TreeNode* temp = q.front();
                q.pop();
                if(temp->val > value && temp->val > max){
                    flag1 = 1;
                    first = temp;
                    max = temp->val;
                }
                if(temp->left) q.push(temp->left);
                if(temp->right) q.push(temp->right);
            }
        }
        //以当前节点为根节点,找右数中是否存在比它的val小的节点,且最小
        if(root->right){
            q.push(root->right);
            int min = value;
            while(!q.empty()){
                TreeNode* temp = q.front();
                q.pop();
                if(temp->val < value && temp->val < min){
                    flag2 = 1;
                    second = temp;
                    min = temp->val;
                }
                if(temp->left) q.push(temp->left);
                if(temp->right) q.push(temp->right);
            }
        }
        //此时说明根节点的左子树中的某个节点和右子树的某个节点错误地交换了
        if(flag1 && flag2) {
            swap(first->val,second->val);
            return;
        }
        //此时说明根节点的左子树中的某个节点和根节点错误地交换了
        else if(flag1){
            swap(first->val,root->val);
            return;
        }
        //此时说明根节点的右子树中的某个节点和根节点错误地交换了
        else if(flag2){
            swap(root->val,second->val);
            return;
        }
        //若没有找到,则递归寻找左子树和右子树
        recoverTree(root->left);
        recoverTree(root->right);
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值