二十一:判断二叉树是否是二叉查找树?
二叉查找树:左子树所有结点值均小于它的根结点的值;右子树所有结点值均大于它的根结点值。
别名:二叉搜索树、二叉排序树。
算法一
思路:
根据二叉搜索树特性。
判断当前结点是否是空结点,如果是返回true(空结点属于二叉搜索树)。
判断当前结点值是否在[min,max](开区间)之间,如果不在返回false。
如果在区间内,则递归检查左右子树是否满足条件。
/**
* @description 二叉树是否是二叉搜索树
* @param {*} root 二叉树
*/
function isValidBST(root) {
/**
* @param {*} root 二叉树
* @param {*} min 区间最小值,默认为无穷小
* @param {*} max 区间最大值,默认为无穷大
*/
function dfs(root, min = -Infinity, max = Infinity) {
// 如果空结点返回true
if (!root) return true;
// 如果不在区间内,返回false
if (root.value <= min || root.value >= max) return false;
// 递归左结点,将max值更改为当前结点的值
// 同理递归右节点,将min值更改为当前结点的值
return dfs(root.left, min, root.value) && dfs(root.right, root.value, max);
}
return dfs(root);
}
算法二
思路:
根据二叉树中序遍历特性,依次输出结点值是有序序列。
根据二叉查找树特性,只需要判断该序列是否是递增序列。
声明一个变量用来记录上一个结点的值,默认值为无穷小。
中序遍历(左/中/右):判断当前节点值是否小于等于前一个结点值,如果是返回false。
递归中序遍历:
/*** @description 二叉树是否是二叉搜索树 (中序遍历)
* @param {*} root 二叉树
*/
function isValidBST(root) {
// 默认值为无穷小
let preVal = -Infinity;
function dfs(root) {
if (!root) return true;
const left = dfs(root.left);
// 如果上一个结点值大于等于当前结点的值,返回false
if (preVal >= root.val) return false;
preVal = root.val;
const right = dfs(root.right);
// 返回最终结果
return left && right;
}
return dfs(root);
}
非递归中序遍历:
/**
* @description 二叉树是否是二叉搜索树 (中序遍历)
* @param {*} root 二叉树
*/
function isValidBST(root) {
const stack = [];
// 上一个结点的值,默认无穷小
let preVal = -Infinity;
while (stack.length || root) {
while (root) {
// 入栈
stack.push(root);
root = root.left;
}
// 出栈
root = stack.pop();
// 如果上一个结点值大于等于当前结点的值,返回false
if (preVal >= root.val) return false;
preVal = root.val;
root = root.right;
}
// 遍历结束,说明是二叉搜索树
return true
}