LeetCode 98. Validate Binary Search Tree

来源:互联网 发布:淘宝没发货退款 信誉 编辑:程序博客网 时间:2024/05/16 02:23

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
原创粉丝点击