LeetCode 98. Validate Binary Search Tree

LeetCode 98. Validate Binary Search Tree

题目很短,大概讲的是要求是判断输入是否是一个BST。其中BST的定义如下:

  • 左子树的所有结点都比根小
  • 右子树的所有结点都比根大
  • 所有左子树和右子树都是BST

题目的第一个坑是,题目并没有把BST的全部定义写全了,漏了下面这个:

  • 没有相同值的结点

为了不给大家提示,题目里的例题给的是前序遍历的排序。其实很容易想到只需要做一次中序遍历,然后检查遍历的队列是否是单调递增的就可以了。

中序遍历方法

static list<int> serializeBST;

class Solution {
public:
    bool isValidBST(TreeNode* root) {
        if(root == NULL)
            return true;
        serializeBST.clear();
        printBST(root);
        list<int>::const_iterator i = serializeBST.begin();
        i++;
        list<int>::const_iterator j = serializeBST.begin();
        for(;i != serializeBST.end(); i++,j++)
        {
            if(*j >= *i)
                return false;
        }
        return true;
    }

    void printBST(TreeNode* root)
    {
        if(root != NULL)
        {
            printBST(root->left);
            serializeBST.push_back(root->val);
            printBST(root->right);
        }
        return;
    }

};

二叉树的遍历的递归中,每个结点都需要遍历一次,时间复杂度是O(n),每次list的push_back操作时间复杂度是O(1),最后遍历一次队列时间复杂度是O(n)。所以总的时间复杂度是O(n)+O(n)。而最差情况是严重不平衡的二叉搜索树,递归调用深度是O(n),空间复杂度是O(n)。而list的空间复杂度也是O*(n),所以总的空间复杂度是O(n)。

中序遍历方法

  • 答主用了static关键字,用来在static区上创建一个数组,事实上这样会减低代码的runtime,推荐写进class做为一个private的变量,这样结果一样,也不会那么慢

然后当然没完,这样写的话,无论什么情况,都必须遍历整个二叉树后才能判断是否是BST,这样太笨了,能不能一旦找到了错误的地方就立刻报false呢?这样最坏情况和上次方法一致,但平均时间复杂度变成了O(log*n)。而通过方法一,很明显我们也发现在比较的步骤里,永远只需要前一位和后一位比较大小,所以只需要存前一位的大小就可以了,这样优化的空间复杂度是*O(1)。

优化的中序遍历

class Solution {
private:
    int g_leftmax = -1;
    bool first = true;
public:
    bool isValidBST(TreeNode* root) {
        if(root == NULL)
            return true;

        if(!isValidBST(root->left))
            return false;
        if(!first && root->val <= g_leftmax)
            return false;
        first = false;
        g_leftmax = root->val;
        if(!isValidBST(root->right))
            return false;
        return true;
    }
};

代码更加简洁了,不过这里有几个点要注意的。
- LeetCode最近更新过一次test case,增加了int的边界条件,最小的结点值可以去到INT_MIN,所以如果不用first判断是否第一次的话,很有可能会出现第一个点的值就等于g_leftmax,从而报false。当然,网上有一些是将g_leftmax实现为一个初始值为NULL的TreeNode指针,这样就可以通过判断指针是否为空来判断是否为第一次

优化的中序遍历

这样就快多了,而且空间复杂度也优化了不少。

既然有递归,我们自然可以用栈来做非递归的方法,这样理论上可以降低递归深度很大的时候的函数调用的时间开销。(但结果是栈实现的方法runtime更加大……这就神奇了。)

用栈实现的非递归方法

class Solution {
public:
    bool isValidBST(TreeNode* root) {
        stack<TreeNode*> s;
        TreeNode *p = root, *pleftmax= NULL;
        while (p || !s.empty()) {
            while (p) {
                s.push(p);
                p = p->left;
            }
            TreeNode *t = s.top(); s.pop();
            if (pleftmax&& t->val <= pleftmax->val) 
                return false;
            pleftmax= t;
            p = t->right;
        }
        return true;
    }
};

拓展

这道题拓展开来,可以有:

  • 左子树小于等于根结点,而右子树大于根结点,这样中序历遍就无法解决问题了(10,10到底是左子树是10–合法,还是右子树是10–非法)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值