【3】验证二叉搜索树(LeetCode 98)

问题描述

验证二叉搜索树

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

有效二叉树的特征:

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

思考过程

容易想到的就是用递归进行判断,出现不满足的情况就返回false,否则就以相同的方式继续检查左子树和右子树。由此写出的代码:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool temp=true;
    bool isValidBST(TreeNode* root) {
        if(root==nullptr)
            return true;
        if(root->left!=nullptr ){
            if((root->left->val) >= (root->val))
                temp=false;
            else 
                temp=isValidBST(root->left);
        }
        if(root->right!=nullptr ){
            if((root->right->val) <= (root->val))
                temp=false;
            else 
                temp=isValidBST(root->right);
        }
        return temp;
    }
};

但是提交之后报错,才发现我忽略了一种情况。
在这里插入图片描述
树结构可视化:
在这里插入图片描述
如上数值为3的节点,它满足了小于6,但是却没有满足大于5,因此应该返回false。但上述代码并不能实现。

发现错误之后我尝试了多种解决方案,比如类似人工智能里最大最小树用α-β算法进行剪枝,我引入了两个全局变量进行比较,但是发现并不能用简单的左右子树来区分当前节点值应该小于或大于α-β的值;然后又用一个全局变量tempval来实现,但是又出现了当递归向前返回时tempval不会恢复之前的值的问题。

磨了几个小时,最终还是看了题解…


题解

递归

官方题解用的递归函数同时还传进去了一个范围,若节点的值不在此范围内则返回false,否则更新范围并继续在左右子树中进行判断。

class Solution {
public:

    bool isValid(TreeNode* root,long long int min_val,long long int max_val){
        if(root==nullptr)
            return true;
        if(root->val <= min_val || root->val >= max_val)
            return false;
        return isValid(root->left,min_val,root->val) && isValid(root->right,root->val,max_val);
    }

    bool isValidBST(TreeNode* root) {
        return isValid(root,LONG_MIN, LONG_MAX);       
    }
};

时间复杂度:O(n)
空间复杂度:O(n)

中序遍历

如果能想到“一棵二叉树若满足题目所述性质,则其中序遍历结果是按从小到大排序的数集”的话,这题就变得简单了——进行中序遍历并检查后一个节点的值是否大于前一个节点的值,若是则继续遍历,否则返回false。

官方是用栈的方式实现中序遍历:

class Solution {
public:
    bool isValidBST(TreeNode* root) {
        stack<TreeNode*> stack;
        long long inorder = (long long)INT_MIN - 1;

        while (!stack.empty() || root != nullptr) {
            while (root != nullptr) {
                stack.push(root);
                root = root -> left;
            }
            root = stack.top();
            stack.pop();
            if (root -> val <= inorder) {
                return false;
            }
            inorder = root -> val;
            root = root -> right;
        }
        return true;
    }
};

也可以用递归的方式实现中序遍历:

class Solution {
public:
    long long temp_val=LONG_MIN;
    bool res=true;

    bool isValidBST(TreeNode* root) {
        if(res==false)
            return res;
        if(root==nullptr)
            return true;

       isValidBST(root->left);
       if(root->val<=temp_val)
            res = false;
        temp_val=root->val;
        isValidBST(root->right);
        
        return res;
    }
};

时间复杂度:O(n)
空间复杂度:O(n)

不过从实际运行结果来看,中序遍历的方法无论是从时间上还是空间上都没有递归的方式优。


心得

坚信量变引起质变的第三天,冲!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值