原题链接:98. 验证二叉搜索树
目录
解法一:(推荐)
思路:
如果一个二叉树是有效的二叉搜索树,那么使用中序遍历则一定可以得到一个有序的序列。所以问题就变为在中序遍历的同时判断二叉树是不是有序的。
解题步骤:
(1)使用一个长整型变量prev记录前一个结点的值,cur.val为当前结点的值
(2)判断当前节点值是否大于中序遍历中的前一个节点的值,若大于则继续递归,否则返回false。
PS: 因为题目给出的最小值为 -2^31,所以需要用一个比它更小的值表示第一个中序遍历结点的前一个值)
算法实现:
这里使用序列 [5,4,6,null,null,3,7] 做例子。
代码
/**
* 时间复杂度:O(n) n为树结点个数,每个结点需要被访问一次。
*
* 空间复杂度:O(n) n为树结点个数,函数递归过程中需要在栈上开辟的空间,最坏情况下,
* 树为单分支链表,递归层次达到n,空间复杂度为O(n);
*/
public class IsValidBST {
private long prev = Long.MIN_VALUE;
public boolean isValidBST(TreeNode root) {
if (root == null) return true; //空直接返回true
if (!isValidBST(root.left)) { //若左子树不满足条件则返回false
return false;
}
if (root.val > prev) { //判断当前节点值是否大于中序遍历中的前一个节点的值,若大于则继续递归,否则返回false。
prev = root.val; //prev改为当前结点
return isValidBST(root.right);
} else {
return false;
}
}
}
递归过程图:
解法二:
思路:
使用中序遍历将各结点值放入list中,然后遍历list,如果list有序则是有效的二叉搜索树,否则不是。
解题步骤:
(1)创建list用来保存结点值。
(2)中序遍历树,并添加各结点
(3)再遍历list判断是否为有序的
代码
/**
* 时间复杂度:0(2N),去掉常数项为0(N) N为树的结点个数,遍历树一次为N,遍历list一次也为N。
*
* 空间复杂度:O(N) 而且还要考虑list扩容耗费的时间,若直接将list初始化为最大则浪费大量空间。
*/
ArrayList<Integer> list = new ArrayList<>();
public boolean isValidBST(TreeNode root) {
inorder(root);
for(int i = 0; i < list.size() - 1; i++){
if(list.get(i) >= list.get(i+1)){
return false;
}
}
return true;
}
public void inorder(TreeNode root){
if(root == null){
return;
}
isValidBST(root.left);
list.add(root.val);
isValidBST(root.right);
}