zoukankan      html  css  js  c++  java
  • 98. 验证二叉搜索树

    98. 验证二叉搜索树

    题目链接:98. 验证二叉搜索树(中等)

    给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

    有效 二叉搜索树定义如下:

    • 节点的左子树只包含 小于 当前节点的数。

    • 节点的右子树只包含 大于 当前节点的数。

    • 所有左子树和右子树自身必须也是二叉搜索树。

    示例 1:

    输入:root = [2,1,3]
    输出:true

    示例 2:

    输入:root = [5,1,4,null,null,3,6]
    输出:false
    解释:根节点的值是 5 ,但是右子节点的值是 4 。

    解题思路

    易错点

    一上来看到题目就开始写代码,这很简单嘛!殊不知掉进陷阱了~

    //递归,但是有问题,这只能说明 根节点 大于 左子节点,小于 右子节点,
    //不能说明 根节点 大于 左子树的所有节点,小于 右子树的所有节点
    class Solution1 {
    public:
        bool isValidBST(TreeNode* root) {
            if (root == nullptr) return true;
            if (root->left != nullptr && root->val <= root->left->val) return false;
            if (root->right!= nullptr && root->val >= root->right->val) return false;
            bool result1 = isValidBST(root->left);
            bool result2 = isValidBST(root->right);
            return result1 && result2;
        }
    };

    上面的写法不能判断 根节点 大于 其左子树所有的节点,只能说明 根节点 大于 其左节点。同理也不能判断 根节点 小于 其右子树所有的节点,只能说明 根节点 小于 其右节点。

    方法一:递归(借助一个数组)

    二叉搜索树的特点是:将二叉搜索树进行中序遍历,并将遍历的结果存在数组中,那该数组一定是有序的(一般是递增的)。

    所以可以按照叉搜索树的这一特征判断二叉树是否是二叉搜索树。

    首先需要借助一个数组,然后对二叉树进行中序遍历并将遍历结果存入数组中,最后对数组进行判断。

    代码

    C++
    //在中序遍历下,输出的二叉搜索树节点的数值是有序序列
    class Solution {
    public:
        vector<int> valVec;
        //将二叉搜索树根据中序遍历转为数组
        void traversal(TreeNode* root) {
            if (root == nullptr) return;
            traversal(root->left); //
            valVec.push_back(root->val); //
            traversal(root->right); //
        }
        bool isValidBST(TreeNode* root) {
            valVec.clear();
            traversal(root);
            int value = valVec[0];
            // 如果数组是单调递增的,则为二叉搜索树,否则不是
            for (int i = 1; i < valVec.size(); i++) {
                if (value < valVec[i]) value = valVec[i];
                else return false;
            }
            return true;
        }
    };
    JavaScript
    //辅助数组
    let nums = [];
    function traversal(root) {
        if (root === null) return;
        traversal(root.left);
        nums.push(root.val);
        traversal(root.right);
    }
    var isValidBST = function(root) {
        nums = [];
        traversal(root);
        var value = nums[0];
        for (var i = 1; i < nums.length; i++) {
            if (value >= nums[i]) return false;
            value = nums[i];
        }
        return true;
    };

    方法二:递归

    不转变成数组,直接在递归遍历的过程中判断二叉树是否有序。

    代码

    C++
    //在递归中直接判断二叉树是否是二叉搜索树(中序遍历)
    class Solution3 {
    public:
       TreeNode* pre = nullptr; //定义一个节点来保存先前节点
        bool isValidBST(TreeNode* root) {
            if (root == nullptr) return true;
            bool leftResult = isValidBST(root->left);
            if (pre != nullptr && pre->val >= root->val) return false;
            pre = root;
            bool rightResult = isValidBST(root->right);
            return leftResult && rightResult;
        }
    };
    JavaScript
    /*****************该方法有问题****************************/
    //记录前一个节点
    let pre = null;
    var isValidBST = function(root) {
        if (root === null) return true;
        let leftResult = isValidBST(root.left);
        if (pre != null && pre.val >= root.val) return false;
        pre = root; // 记录前一个节点
        let rightResult = isValidBST(root.right);
        return leftResult && rightResult;
    };

    方法三:迭代

    借助“栈”进行中序遍历的迭代,类似于二叉树的迭代遍历 二叉树的统一迭代遍历 中的中序遍历。

    代码

    C++
    //统一迭代法(栈,中序遍历)
    class Solution4 {
    public:
        bool isValidBST(TreeNode* root) {
            stack<TreeNode*> nodeSta;
            if (root != nullptr) nodeSta.push(root);
            TreeNode* pre = nullptr; //记录前一个节点
            while (!nodeSta.empty()) {
                TreeNode* node = nodeSta.top();
                if (node != nullptr) {
                    nodeSta.pop();
                    if (node->right) nodeSta.push(node->right); //
                    nodeSta.push(node); //
                    nodeSta.push(nullptr); //null
                    if (node->left) nodeSta.push(node->left); //
                } else {
                    nodeSta.pop();
                    if (pre != nullptr && pre->val >= nodeSta.top()->val) return false;
                    pre = nodeSta.top();
                    nodeSta.pop();
                }
            }
            return true;
        }
    };
    ​
    //迭代法(栈,中序遍历)
    class Solution5 {
    public:
        bool isValidBST(TreeNode* root) {
            stack<TreeNode*> nodeSta;
            TreeNode* cur = root;
            TreeNode* pre = nullptr; //记录前一个节点
            while (cur != nullptr || !nodeSta.empty()) {
                if (cur != nullptr) {
                    nodeSta.push(cur);
                    cur = cur->left;
                } else {
                    cur = nodeSta.top();
                    nodeSta.pop();
                    if (pre != nullptr && pre->val >= cur->val) return false;
                    pre = cur;
                    cur = cur->right;
                }
            }
            return true;
        }
    };
    JavaScript
    //迭代法
    var isValidBST = function(root) {
        let nodeSta = [];
        let cur = root;
        let pre = null;
        while(cur != null || nodeSta.length != 0) {
            if (cur != null) {
                nodeSta.push(cur);
                cur = cur.left;
            } else {
                cur = nodeSta.pop();
                if (pre != null && pre.val >= cur.val) return false;
                pre = cur;
                cur = cur.right;
            }
        }
        return true;
    };

     

  • 相关阅读:
    win8 app scrollviewer ZoomMode
    win8 metro app 不支持 trigger
    WinRT Convert Stream to BitmapImage
    Java深度历险(二)——Java类的加载、链接和初始化(收藏)
    简单的触发器实现
    Java深度历险(一)——Java字节代码的操纵(收藏)
    借用网上大神的一些知识,html5 video 视频播放都兼容(Android,iOS,电脑)
    还原或删除sql server 2008数据库时,经常烩出现: “因为数据库正在使用,所以无法获得对数据库的独占访问权”,终解决方案
    调研《构建之法》指导下的历届作品
    Hibernate 学习笔记一
  • 原文地址:https://www.cnblogs.com/wltree/p/15681731.html
Copyright © 2011-2022 走看看