判断一棵树是否是合法二叉树

题目:给定一棵树,判断是否是合法的二叉搜索树。
如果合法返回true,不合法则返回false。

首先,应该明确二叉搜索树的定义,二叉搜索树是一个递归的定义,即二叉搜索树的左子节点小于根节点,而右节点大于根节点,同时左右子树也是一棵二叉搜索树。

错误的想法:
先判断根节点和左右子节点的大小关系,如果不符合大小关系,直接返回false。如果符合,则递归调用判断左右子树是否合法。
如下:

/**
* 验证是否是合法二叉搜索树
 */
public boolean isValidBST(TreeNode root) {
    if (root == null) {
        return true;
    }
	
	// 判断根节点与左子节点的关系
    boolean isLeftValid = true;
    if (root.left != null) {
        isLeftValid = root.val > root.left.val;
    }

	// 判断根节点与右子节点的关系
    boolean isRightValid = true;
    if (root.right != null) {
        isRightValid = root.val < root.right.val;
    }
	
	// 左子点及右子节点递归调用,判断是否符合这种大小关系
    return isLeftValid && isRightValid && isValidBST(root.left) && isValidBST(root.right);
}

这种想法只考虑了根节点与其左右子节点的关系,即只考虑了每三个节点之前的大小关系,而没有考虑子节点与所有剩余子节点的大小关系。
如对于如下的二叉树则会得到错误结果:

				4
		1				6
	0	    2     3		7

这棵二叉树很显然不是二叉搜索树,因为其中的3小于4。

正确的解法一

/**
* 验证是否是合法二叉搜索树
*/
public boolean isValidBST(TreeNode root) {
   return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
}

/**
* 当前root值的上下界要在指定的范围内
* @param root
* @param lower 下界
* @param upper 上界 
* @return
*/
public boolean isValidBST(TreeNode root, long lower, long upper) {
   if (root == null) {
       return true;
   }

   // 不符合搜索树的定义
   if (root.val <= lower || root.val >= upper) {
       return false;
   }

   return isValidBST(root.left, lower, root.val) && isValidBST(root.right, root.val, upper);
}

正确的解法二:

// 用long型的数据来记录前一个节点,int型过不了leetcode测试用例
long pre = Long.MIN_VALUE;
/**
 * @param root
 * @return 本质上还是利用了中序的排序性质,只是用了递归的方式。
 */
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);
}

正确的解法三:
利用二叉搜索树的中序遍历有序性,边遍历边比较。

/**
 * 在遍历的过程中比较, 在leetcode上这种方式的时间还没有上面的递归调用快。 
 */
public boolean isValidBST3(TreeNode root) {
    if (root == null) {
        return true;
    }

    Deque<TreeNode> stack = new ArrayDeque<TreeNode>();
    TreeNode cur = root;
    // stack是空的,故加入cur不为空的判断
    while (!stack.isEmpty() || cur != null) {
        while (cur != null) {
            stack.push(cur);
            cur = cur.left;
        }

        TreeNode tmp = stack.pop();
        if (tmp.val <= pre) {
            return false;
        } else {
            pre = tmp.val;
        }

        cur = tmp.right;
        // 这里不能在push了,因为cur在while循环开头就会push,如果这里push就会push两次了。 
        // if (cur != null) {
            // stack.push(cur);
        // }
    }

    return true;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章