首页

验证二叉搜索树

一、接雨水

难度:中等

题目传送门:验证二叉搜索树

题目

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效二叉搜索树定义如下:

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

示例 1:

输入:root = [2,1,3]

输出:true

示例 2:

输入:root = [5,1,4,null,null,3,6]

输出:false

解释:根节点的值是 5 ,但是右子节点的值是 4 。

提示:

  1. 树中节点数目范围在[1, 104] 内
  2. -2^31 <= Node.val <= 2^31 - 1

思路

要确保是正确的二叉搜索树,则需要保证左小右大。如果所有父节点均满足此要求,则二叉搜索树合法。

由此可以看出这是一道典型的递归题。从root节点开始,如果左子树存在,则左子树成为判断的子树;同理右子树也是一样。

由于是二叉搜索树,则按照中序遍历的方法,则打印出来的结果应该是递增的序列。反映到算法上,则上一个节点值需要小于下一个节点值。

实现起来,先判断左节点,然后判断parent,然后判断右节点。保留上一个节点的值,当判断当前节点(current parent node)的时候,比较其大小,如果上一个节点值大于或者等于当前节点值,则返回false。

这种方法下:

  1. 每一个元素需要一次遍历,时间复杂度为O(n);
  2. 需要保留上一个节点值,空间复杂度为O(1)。(实现时要考虑到递归产生的方法栈,实际消耗的内存会比较多)

代码

先上测试

func Test_numTrees(t *testing.T) {
	d1 := &TreeNode{
		Val:   2,
		Left:  &TreeNode{Val: 1},
		Right: &TreeNode{Val: 3},
	}
	d2 := &TreeNode{
		Val:  5,
		Left: &TreeNode{Val: 1},
		Right: &TreeNode{Val: 4,
			Left:  &TreeNode{Val: 3},
			Right: &TreeNode{Val: 6},
		},
	}
	d3 := &TreeNode{
		Val: 0,
	}
	d4 := &TreeNode{
		Val:  1,
		Left: &TreeNode{Val: 1},
	}
	// 根据题意,对边界做一个测试
	d5 := &TreeNode{
		Val: -2147483648,
	}

	inputs := []*TreeNode{d1, d2, d3, d4, d5}
	expects := []bool{true, false, true, false, true}
	for i := 0; i < len(inputs); i++ {
		got := isValidBST(inputs[i])
		expected := expects[i]
		if expected != got {
			t.Errorf("[%d] want %v,got %v", i+1, expected, got)
		}
	}
}

方法实现

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */

var pre int

func isValidBST(root *TreeNode) bool {
	// 每次进来重置pre
	pre = 1 << 31 * -1 -1
	return helper(root)
}

func helper(root *TreeNode) bool {
	if root == nil {
		return true
	}
	if !helper(root.Left) {
		return false
	}
	if root.Val <= pre {
		return false
	}
	pre = root.Val
	return helper(root.Right)
}

性能

来自Leetcode, 0表示小于1个单位。

执行用时: 8 ms
内存消耗: 5 MB