Java实现判断一棵树是否为BST二叉搜索树

标题:Java实现判断一棵树是否为BST二叉搜索树

题目:判断是否为二叉搜索树
98. 验证二叉搜索树

给定一个二叉树,判断其是否是一个有效的二叉搜索树。

假设一个二叉搜索树具有如下特征:

    节点的左子树只包含小于当前节点的数。
    节点的右子树只包含大于当前节点的数。
    所有左子树和右子树自身必须也是二叉搜索树。

示例 1:

输入:
    2
   / \
  1   3
输出: true

示例 2:

输入:
    5
   / \
  1   4
     / \
    3   6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
     根节点的值为 5 ,但是其右子节点值为 4/*方法一:递归,使用long  【相当于补全BST】
执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
内存消耗:37.7 MB, 在所有 Java 提交中击败了97.73% 的用户
*/
public int isValidBST(TreeNode root) {
	return this.preorder(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
public boolean preorder(TreeNode root, long min, long max){
	if(root == null){
		return true;
	}else if(root.val <= min || root.val >= max){
		return false;
	}else{
		boolean b1 = this.preorder(root.left, min, root.val);
		boolean b2 = this.preorder(root.right, root.val, max);
		
		return b1 && b2;
	}
}


上述的示意图:
在这里插入图片描述

/*方法二:递归,使用节点TreeNode,思想同上 
执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
内存消耗:38.2 MB, 在所有 Java 提交中击败了69.92% 的用户
*/
public boolean isValidBST(TreeNode root) {
	return this.preorder(root, null, null);
}
public boolean preorder(TreeNode root, TreeNode min, TreeNode max){
	if(root == null){
		return true;
	}else if(min != null && root.val <= min.val){
		return false;
	}else if(max != null && root.val >= max.val){
		return false;
	}else{
		boolean b1 = this.preorder(root.left, min, root);
		boolean b2 = this.preorder(root.right, root, max);
		
		return b1 && b2;
	}
}
//上述两个方法的非递归遍历   【这个迭代特别有想法】
执行用时:4 ms, 在所有 Java 提交中击败了5.41% 的用户
内存消耗:38.1 MB, 在所有 Java 提交中击败了71.77% 的用户
public boolean isValidBST(TreeNode root){
	if(root == null){
		return true;
	}
	
	Deque<TreeNode> s = new LinkedList<>();
	s.push(root);
	
	Deque<Long> minS = new LinkedList<>();
	Deque<Long> maxS = new LinkedList<>();
	minS.push(Long.MIN_VALUE);
	maxS.push(Long.MAX_VALUE);
	
	while(!s.isEmpty()){
		TreeNode p = s.pop();
		long min = minS.pop();
		long max = maxS.pop();
		
		if(p.val <= min || p.val >= max){
			return false;
		}
		if(p.right != null){
			s.push(p.right);
			minS.push((long)p.val);
			maxS.push(max);
		}
		if(p.left != null){
			s.push(p.left);
			minS.push(min);
			maxS.push((long)p.val);
		}
	}
	
	return true;
}


/*
方法三:递归:使用一个节点pre  --》 使用long pre = Long.MIN_VALUE;
执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
内存消耗:38.1 MB, 在所有 Java 提交中击败了74.91% 的用户
*/
private TreeNode pre;
public boolean isValidBST(TreeNode root) {
	return this.preorder(root);
}
public boolean preorder(TreeNode root){
	if(root == null){
		return true;
	}else{
		boolean b1 = this.preorder(root.left);
		if(pre != null && root.val <= pre.val){
			return false;
		}
		pre = root;
		
		boolean b2 = this.preorder(root.right);
		
		return b1 && b2;
	}
}

//非递归实现
执行用时:3 ms, 在所有 Java 提交中击败了8.53% 的用户
内存消耗:37.8 MB, 在所有 Java 提交中击败了95.85% 的用户
public boolean isValidBST(TreeNode root){
	if(root == null){
		return true;
	}
	
	Deque<TreeNode> s = new LinkedList<>();
	s.push(root);
	TreeNode pre = null;
	
	while(!s.isEmpty()){
		TreeNode p = s.peek();
		if(p.left != null){
			s.push(p.left);
		}else{
			s.pop();
			//sout;
			if(pre != null && pre.val >= p.val){
				return false;
			}
			pre = p;
			while(p.right == null && !s.isEmpty()){
				p = s.pop();
				//sout;
				if(pre != null && pre.val >= p.val){
					return false;
				}
				pre = p;
			}
			if(p.right != null){
				s.push(p.right);
			}else{
				break;
			}
		}
	}
	
	return true;
}

/*
方法四:对于每一个node,
要求:right一步,一直向左走,找到leftNode, 要求node.val < leftNode
      left一步,一直向右走,找到rightNode, 要求node.val > rightNode
执行结果:
通过
显示详情
执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
内存消耗:38.1 MB, 在所有 Java 提交中击败了78.48% 的用户
*/
public boolean isValidBST(TreeNode root) {
	if(root == null){
		return true;
	}else{
		if(root.left != null){
			TreeNode leftMax = this.getLeftMax(root.left);
			if(root.val <= leftMax.val){
				return false;
			}
		}
		if(root.right != null){
			TreeNode rightMin = this.getRightMin(root.right);
			if(root.val >= rightMin.val){
				return false;
			}
		}
		return isValidBST(root.left) && isValidBST(root.right);
	}

}
private TreeNode getRightMin(TreeNode root){
	while(root.left != null){
		root = root.left;
	}
	
	return root;
}
private TreeNode getLeftMax(TreeNode root){
	while(root.right != null){
		root = root.right;
	}
	
	return root;
}

/*
方法五:中序得到list,看是否有后面一个val > 前面一个value
执行用时:2 ms, 在所有 Java 提交中击败了30.67% 的用户
内存消耗:38.4 MB, 在所有 Java 提交中击败了51.64% 的用户
*/
public boolean isValidBST(TreeNode root) {
	List<Integer> list = new ArrayList<>();
	this.inorder(root, list);
	
	for(int i = 1; i < list.size(); i++){
		if(list.get(i) <= list.get(i - 1)){
			return false;
		}
	}
	
	return true;

}
private void inorder(TreeNode root, List<Integer> list){
	if(root == null){
		return ;
	}else{
		this.inorder(root.left, list);
		list.add(root.val);
		this.inorder(root.right, list);
	}
}


//
boolean isValidBST(TreeNode root) {
    return isValidBST(root, null, null);
}

boolean isValidBST(TreeNode root, TreeNode min, TreeNode max) {
    if (root == null) return true;
    if (min != null && root.val <= min.val) return false;
    if (max != null && root.val >= max.val) return false;
    return isValidBST(root.left, min, root) 
        && isValidBST(root.right, root, max);
}

// 将我的TreeNode 变成了long
long pre = Long.MIN_VALUE; 

public boolean isValidBST(TreeNode root) {
	if(root==null) return true;

	if(!isValidBST(root.left)) return false; //访问左子树
	if(root.val <= pre) return false; //当前节点是否小于上一节点的值
	pre = root.val; 
	return isValidBST(root.right); //访问右子树
}


//
public boolean isValidBST(TreeNode root) {
        Deque<TreeNode> stack = new LinkedList<TreeNode>();
        double inorder = -Double.MAX_VALUE;

        while (!stack.isEmpty() || root != null) {
            while (root != null) {
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
              // 如果中序遍历得到的节点的值小于等于前一个 inorder,说明不是二叉搜索树
            if (root.val <= inorder) {
                return false;
            }
            inorder = root.val;
            root = root.right;
        }
        return true;
    }

开始一步步的推导

//全
我们从简单的前序递归开始

class Solution {
    public boolean isValidBST(TreeNode root) {
        return dfs(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }
    boolean dfs(TreeNode node, long lower, long upper) {
        if (node == null) 
            return true;
        if (node.val <= lower) 
            return false;
        if (node.val >= upper) 
            return false;
        if (!dfs(node.left, lower, node.val)) 
            return false;
        if (!dfs(node.right, node.val, upper)) 
            return false;
        return true;
    }
}

写花哨一点是:

class Solution {
    public boolean isValidBST(TreeNode root) {
        return dfs(root, java.lang.Long.MIN_VALUE, java.lang.Long.MAX_VALUE);
    }
    boolean dfs(TreeNode node, long min, long max) {
        return (node == null) || node.val > min && node.val < max && dfs(node.left, min, node.val) && dfs(node.right, node.val, max);
    }
}

如果不用递归,而用栈实现前序:  【写的特别好,这个迭代】

class Solution {
    Stack<TreeNode> st = new Stack<>();
    Stack<Long> upperList = new Stack<>(), 
        lowerList = new Stack<>();
        
    public boolean isValidBST(TreeNode root) {
        long lower = Long.MIN_VALUE, upper = Long.MAX_VALUE, val;
        update(root, lower, upper);
        while (!st.empty()) {
            root = st.pop();
            lower = lowerList.pop();
            upper = upperList.pop();
            if (root == null) continue;
            val = (long)root.val;
            if (val <= lower) return false;
            if (val >= upper) return false;
            update(root.right, val, upper);
            update(root.left, lower, val);
        }
        return true;
    }

    void update(TreeNode node, long lower, long upper) {
        st.push(node);
        lowerList.push(lower);
        upperList.push(upper);
    }
}

仅仅将栈改为队列,就实现了广度优先:

class Solution {
    Queue<TreeNode> queue = new LinkedList<>();
    Queue<Long> upperList = new LinkedList<>(), 
        lowerList = new LinkedList<>();
        
    public boolean isValidBST(TreeNode root) {
        long lower = Long.MIN_VALUE, upper = Long.MAX_VALUE, val;
        update(root, lower, upper);
        while (!queue.isEmpty()) {
            root = queue.poll();
            lower = lowerList.poll();
            upper = upperList.poll();
            if (root == null) continue;
            val = root.val;
            if (val <= lower) return false;
            if (val >= upper) return false;
            update(root.left, lower, val);
            update(root.right, val, upper);
        }
        return true;
    }

    void update(TreeNode root, long lower, long upper) {
        queue.offer(root);
        lowerList.offer(lower);
        upperList.offer(upper);
    }
}

现在换回栈,但改用中序排序
执行用时:2 ms, 在所有 Java 提交中击败了30.67% 的用户
内存消耗:38.1 MB, 在所有 Java 提交中击败了80.63% 的用户
class Solution {
    public boolean isValidBST(TreeNode root) {
        Stack<TreeNode> st = new Stack<>();
        long lastVal = Long.MIN_VALUE;
        
        while (!st.empty() || root != null) {
            while(root != null) {
                st.push(root);
                root = root.left;
            }
            root = st.pop();
            if (root.val <= lastVal) return false;
            lastVal = (long)root.val;
            root = root.right;
        }
        return true;
    }
}

用递归来实现中序,往上翻看看和前序递归有什么区别,想一想为什么中序只需判断一次节点值的大小

class Solution {
    long lastVal = Long.MIN_VALUE;
    public boolean isValidBST(TreeNode root) {
        return dfs(root);
    }
    boolean dfs(TreeNode node) {
        if (node == null)
            return true;
        if (!dfs(node.left))
            return false;
        if (node.val <= lastVal) 
            return false;
        lastVal = (long) node.val;
        if (!dfs(node.right))
            return false;
        return true;
    }
}

dfs和isValidBST 在参数返回值一致,可以把这两个合并为一个

class Solution {
    long lastVal = Long.MIN_VALUE;
    public boolean isValidBST(TreeNode root) {
        if (root == null)
            return true;
        if (!isValidBST(root.left))
            return false;
        if (root.val <= lastVal) 
            return false;
        lastVal = (long) root.val;
        if (!isValidBST(root.right))
            return false;
        return true;
    }
}

写得花哨一点就只剩一行

class Solution {
    long lastVal = Long.MIN_VALUE;
    public boolean isValidBST(TreeNode root) {
        return (root == null) || (isValidBST(root.left) && lastVal < (lastVal = root.val) && isValidBST(root.right));
    }
}


//再写前面的两个递归方法
//递归,方法一:
public boolean isValidBST(TreeNode root){
	return this.isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
public boolean isValidBST(TreeNode root, long min, long max){
	if(root == null){
		return true;
	}else {
		if(root.val <= min || root.val >= max){
			return false;
		}
		boolean b1 = isValidBST(root.left, min, root.val);
		boolean b2 = isValidBST(root.right, root.val, max);
		
		return b1 && b2;
	}
}

//递归,方法二:
public boolean isValidBST(TreeNode root){
	return this.isValidBST(root, null, null);
}
public boolean isValidBST(TreeNode root, TreeNode tMin, TreeNode tMax){
	if(root == null){
		return true;
	}else {
		if(tMin != null && root.val <= tMin.val){
			return false;
		}
		if(tMax != null && root.val >= tMax.val){
			return false;
		}
		boolean b1 = isValidBST(root.left, tMin, root);
		boolean b2 = isValidBST(root.right, root, tMax);
		
		return b1 && b2;
	}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值