题目来源:

1
2
3
4
5
6
7
输入:
2
/ \
1 4
/ \
3 5
输出: true
1
2
3
4
5
6
7
输入:
5
/ \
1 4
  / \
  3 6
输出: false

起初使用堆的方式判定是不对的,二叉搜索树的任意结点应该 总大于所有左子树结点以及总小于所有右子树结点,不能只与左右孩子比较。

分析:(两种解法)

  • 方法一:递归求解。设定上下界,如果当前结点在上下界内则是符合的。
  1. 如果是空树,则认为是 BST,返回true
  2. 非空,若 <= 下界 或 >= 上界 则返回false
  3. 以上条件均不满足,则递归判断左右孩子是否为 BST
    • 向左递归时,左孩子应该均小于当前结点,故更新上界为当前结点的值
    • 向右递归时,同理,右孩子均大于当前结点,故更新下界为当前结点数值
1
2
3
4
5
6
7
8
9
10
11
12
bool isValidBST(node* root, int low, int high) {
if (root == NULL) return true;
if (root->val <= low || root->val >= high) return false;
return isValidBST(root->left, low, root->val)
&& isValidBST(root->right, root->val, high);
}

int main() {
node *root = initBinaryTree();
isBST(root, INT_MIN, INT_MAX);
return 0;
}

调用时,初始的上下界为整型可表示的最小最大值。

  • 方法二:迭代。二叉搜索树的中序遍历序列是升序的,只需要判断中序序列中两个相邻元素的大小关系即可,使用preValue记录前一个结点的值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
bool isValidBST(node* root) {
stack<node*> s;
node* p = root;
long preValue = LONG_MIN; // 定义最小值
while (!s.empty() || p != NULL) {
for (;p != NULL; p = p->left) s.push(p); // 左孩子不为NULL, 一直入栈
p = s.top();
s.pop();
if (p->val <= preValue) return false; // 如果不符合则直接返回 false
preValue = p->val;
p = p->right;
}
return true;
}
  • 方法三:同为递归求解,但相对耗时。根据BST性质,判断当前节点是不是总比左子树的最右端的孩子大且总比右子树的最左端孩子小。缺点是对任意结点总要查找一次上面描述的最左右端的结点。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
bool isValidBST(TreeNode* root) {
if (root == NULL) return true;
TreeNode* p = root->left;
if (p) {
while (p->right) p = p->right;
if (root->val <= p->val) return false;
}
p = root->right;
if (p) {
while (p->left) p = p->left;
if (root->val >= p->val) return false;
}
return isValidBST(root->left) && isValidBST(root->right);
}