Day111 | 灵神 | 二叉树 | 验证二叉搜索树

发布于:2025-05-07 ⋅ 阅读:(45) ⋅ 点赞:(0)

Day111 | 灵神 | 二叉树 | 验证二叉搜索树

98.验证二叉搜索树

98. 验证二叉搜索树 - 力扣(LeetCode)

方法一:前序遍历

image-20250506121206361

递归函数传入合法的左右边界,只有当前结点是合法的边界,才是二叉搜索树,否则就返回false

对于左子树就传入当前结点的左边界,和当前结点的值作为右边界,从而验证左子树是一颗二叉搜索树

对于右子树就传入当前结点的右边界,和当前结点的值作为左边界,从而验证右子树是一颗二叉搜索树

只有当前结点符合条件并且左右子树也都是二叉搜索树才会返回true

灵神前序遍历代码:

class Solution {
public:
    bool isValidBST(TreeNode* root, long long left = LLONG_MIN, long long right = LLONG_MAX) {
        if (root == nullptr) {
            return true;
        }
        long long x = root->val;
        return left < x && x < right &&
               isValidBST(root->left, left, x) &&
               isValidBST(root->right, x, right);
    }
};
复杂度分析
  • 时间复杂度:O(n),其中 n 为二叉搜索树的节点个数。
  • 空间复杂度:O(n)。最坏情况下,二叉搜索树退化成一条链(注意题目没有保证它是平衡树),因此递归需要 O(n) 的栈空间。

方法二:中序遍历

二叉树搜索树的中序遍历是一个有序序列,记录前一个值,如果当前结点的值比前一个值小就是false

class Solution {
public:
    TreeNode *pre=nullptr;
    bool tra(TreeNode *t)
    {
        if(t==nullptr)
            return true;
        bool l=tra(t->left);
        if(pre!=nullptr)
            if(t->val<=pre->val)
                return false;
        pre=t;
        bool r=tra(t->right);
        return l&&r;
    }
    bool isValidBST(TreeNode* root) {
        return tra(root);
    }
};

灵神中序遍历代码:

class Solution {
    long long pre = LLONG_MIN;
public:
    bool isValidBST(TreeNode* root) {
        if (root == nullptr) {
            return true;
        }
        if (!isValidBST(root->left) || root->val <= pre) {
            return false;
        }
        pre = root->val;
        return isValidBST(root->right);
    }
};
复杂度分析
  • 时间复杂度:O(n),其中 n 为二叉搜索树的节点个数。
  • 空间复杂度:O(n)。最坏情况下,二叉搜索树退化成一条链(注意题目没有保证它是平衡树),因此递归需要 O(n) 的栈空间。

方法三:后序遍历

灵神后序遍历代码:

class Solution {
    pair<long long, long long> dfs(TreeNode* node) {
        if (node == nullptr) {
            return {LLONG_MAX, LLONG_MIN};
        }
        auto[l_min, l_max] = dfs(node->left);
        auto[r_min, r_max] = dfs(node->right);
        long long x = node->val;
        // 也可以在递归完左子树之后立刻判断,如果发现不是二叉搜索树,就不用递归右子树了
        if (x <= l_max || x >= r_min) {
            return {LLONG_MIN, LLONG_MAX};
        }
        return {min(l_min, x), max(r_max, x)};
    }

public:
    bool isValidBST(TreeNode* root) {
        return dfs(root).second != LLONG_MAX;
    }
};
复杂度分析
  • 时间复杂度:O(n),其中 n 为二叉搜索树的节点个数。
  • 空间复杂度:O(n)。最坏情况下,二叉搜索树退化成一条链(注意题目没有保证它是平衡树),因此递归需要 O(n) 的栈空间。

灵神点评

  • 前序遍历在某些数据下不需要递归到叶子节点就能返回(比如根节点左儿子的值大于根节点的值,左儿子就不会继续往下递归了),而中序遍历和后序遍历至少要递归到一个叶子节点。从这个角度上来说,前序遍历是最快的。
  • 中序遍历很好地利用了二叉搜索树的性质,使用到的变量最少。
  • 后序遍历的思想是最通用的,即自底向上计算子问题的过程。想要学好动态规划的话,请务必掌握自底向上的思想。

网站公告

今日签到

点亮在社区的每一天
去签到