代码随想录刷题攻略--二叉树4--求二叉搜索树的属性

 例题1:二叉搜索树中的搜索

给定二叉搜索树(BST)的根节点 root 和一个整数值 val

你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。

 

 这道题乍一看是简单的递归题,但在单层处理逻辑中,我习惯地写

searchBST(root->left, val),

却忘了递归函数还有返回值。

递归函数的返回值是什么? 是 左子树如果搜索到了val,要将该节点返回。 如果不用一个变量将其接住,那么返回值不就没了

class Solution {
public:
    TreeNode* searchBST(TreeNode* root, int val) {
        if(root ==NULL) return NULL;

        if(root->val == val) return root;
        // else if(root->val < val) searchBST(root->right,val);
        // else searchBST(root->left,val);
        // return NULL; 递归函数的返回值是子树如果搜索到了val,要将该节点返回。 如果不用一个变量将其接住,那么返回值不就没了
        TreeNode *result = NULL;
        if(root->val < val) result = searchBST(root->right,val);
        else if (root->val > val) result = searchBST(root->left,val);
        return result;
    }
};

例题2:验证二叉搜索树

给定一个二叉树,判断其是否是一个有效的二叉搜索树。

假设一个二叉搜索树具有如下特征:

  • 节点的左子树只包含小于当前节点的数。
  • 节点的右子树只包含大于当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

 

 我一开始写的代码是不完全正确的,如下:

  • 陷阱1

class Solution {
    public boolean isValidBST(TreeNode root) {
        //终止条件

        //判断是否为二叉搜索树
        if(root.left!=null && root.right!=null)
        {
            if(root.left.val >= root.val || root.right.val <= root.val)
            return false;
            return isValidBST(root.left)&&isValidBST(root.right);
        }else if(root.left!=null)
        {
            if(root.left.val >= root.val) return false;
            return isValidBST(root.left);
        }else if(root.right!=null)
        {
            if(root.right.val <= root.val) return false;
            return isValidBST(root.right);
        }else 
            return true;
    }
}

因为我单纯比较当前结点和左右子结点的大小,但是 我们要比较的是 左子树所有节点小于中间节点,右子树所有节点大于中间节点。所以以上代码的判断逻辑是错误的。

 正确写法是,我们利用搜索二叉树的特性(左子树的所有结点都比根结点小,右子树的所有结点都比根结点大),将二叉树进行中序遍历,得到一个数组,我们判断其是否有序;

或者也可以节省这个数组,使用一个最小值进行中序遍历,判断下一个结点是否比当前结点的值大。

陷阱2

样例中最小节点 可能是int的最小值,如果这样使用最小的int来比较也是不行的。

此时可以初始化比较元素为longlong的最小值。

class Solution {
    public long maxval = Long.MIN_VALUE;
    public boolean isValidBST(TreeNode root) {
        if(root == null) return true;

        boolean left = isValidBST(root.left);         // 左

        // 中序遍历,验证遍历的元素是不是从小到大
        if (maxval < root.val) maxval = root.val; // 中
        else return false;

        boolean right = isValidBST(root.right);       // 右
        return left && right;
    }
}

问题可以进一步演进:如果样例中根节点的val 可能是longlong的最小值 又要怎么办呢?

 建议避免 初始化最小值,如下方法取到最左面节点的数值来比较。

class Solution {
public:
    TreeNode* pre = NULL; // 用来记录前一个节点
    bool isValidBST(TreeNode* root) {
        if (root == NULL) return true;
        bool left = isValidBST(root->left);

        if (pre != NULL && pre->val >= root->val) return false;
        pre = root; // 记录前一个节点

        bool right = isValidBST(root->right);
        return left && right;
    }
};

例题3:二叉搜索树的最小绝对差

给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。

差值是一个正数,其数值等于两值之差的绝对值。

 跟上一题一样,可以通过中序遍历得到所有树结点,然后遍历一遍数组得到最小差值。

class Solution {
public:
    vector<int> result;
    void traversal(TreeNode* root){
        if(root == NULL) return ;

        traversal(root -> left);
        result.push_back(root -> val);
        traversal(root -> right);
    }

    int getMinimumDifference(TreeNode* root) {
        traversal(root);
        if (result.size() < 2) return 0;
        int num = INT_MAX;
        for (int i = 1; i < result.size(); i++) { // 统计有序数组的最小差值
            num = min(num, result[i] - result[i-1]);
        }
        return num;
    }
};

例题4:把二叉搜索树转换为累加树

给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。

提醒一下,二叉搜索树满足下列约束条件:

  • 节点的左子树仅包含键 小于 节点键的节点。
  • 节点的右子树仅包含键 大于 节点键的节点。
  • 左右子树也必须是二叉搜索树。

 

 

如果使用数组,我们将搜索二叉树进行中序遍历,然后累加,即:数组最后1个值更新为自身,倒数第2个值为自身和最后1个值的累加....

 换算到搜索二叉树,就是从右往左依次累加,也就是 右 -> 中 -> 左 的顺序。

1、递归函数返回类型及参数

根据上述的分析,遍历树不需要传什么参,传一个树结点指针就行。同时还要个全局变量来存储之前的累加值。

2、终止条件

遇空就终止。

3、单层逻辑

traversal(root -> right);

root -> val += total;
total = root -> val;

traversal(root -> left);

整体代码:

class Solution {
public:
    int total = 0;
    
    void traversal(TreeNode* root){
        if(root == NULL) return;

        traversal(root -> right);

        root -> val += total;
        total = root -> val;

        traversal(root -> left);
    }

    TreeNode* convertBST(TreeNode* root) {
        traversal(root);
        return root;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值