今日题目:
目录
今天做的题目都是与二叉搜索树(BST)相关,主要都是利用二叉搜索树的特性和对二叉搜索树的基本增删查操作。
这些题目中,需要着重关注一下"验证二叉搜索树"和“删除二叉搜索树中的节点”这两个题目,稍有难度容易写错。
Problem 1:BST 的特性
BST 的基本特性如下:
- 对于 BST 的每一个节点 node,左子树的节点都比 node 小,右子树的节点都比 node 大
- BST 中每个子树都是 BST
从算法题的角度来看,BST 还有一个重要性质:BST 的中序遍历结果是有序的。
LC 230. 二叉搜索树中第 K 小的元素 【easy】
这个题目利用好 BST 的中序遍历是有序的这个特性,难度不大。
LC 538. 把二叉搜索树转换为累加树 【easy】
本质上还是在考察树的遍历,难度不大。
Problem 2:BST 的基本操作
对于 BST 相关的题目,会经常看到下面这样的代码逻辑:
void BST(TreeNode root, int target) {
if (root.val == target)
// 找到目标,做点什么
if (root.val < target)
BST(root.right, target);
if (root.val > target)
BST(root.left, target);
}
这个代码框架其实和二叉树的遍历框架差不多,无非就是利用了 BST 左小右大的特性而已。接下来看下 BST 这种结构的基础操作是如何实现的。
LC 98. 验证二叉搜索树 【略有难度】 ⭐⭐⭐
这个题有个关键易错点:检查 BST 是否合法不仅仅是判断 root 与其左右子节点,因为 BST 要求 root 的整个左子树都要小于 root.val,整个右子树都要大于 root.val。
问题是,对于某一个节点 root,他只能管得了自己的左右子节点,怎么把 root 的约束传递给左右子树呢?请看正确的代码:
boolean isValidBST(TreeNode root) {
return isValidBST(root, null, null);
}
/* 限定以 root 为根的子树节点必须满足 max.val > root.val > min.val */
boolean isValidBST(TreeNode root, TreeNode min, TreeNode max) {
// base case
if (root == null) return true;
// 若 root.val 不符合 max 和 min 的限制,说明不是合法 BST
if (min != null && root.val <= min.val) return false;
if (max != null && root.val >= max.val) return false;
// 限定左子树的最大值是 root.val,右子树的最小值是 root.val
return isValidBST(root.left, min, root)
&& isValidBST(root.right, root, max);
}
我们通过使用辅助函数,增加函数参数列表,在参数中携带额外信息,将这种约束传递给子树的所有节点,这也是二叉树算法的一个小技巧吧。
LC 700. 二叉搜索树中的搜索 【easy】
这个题就是一道基本题,在二叉搜索树上进行检索。
LC 701. 二叉搜索树中的插入操作 【easy】
这个题目也还好,因为在二叉搜索树上进行插入是最终要插入到叶子节点上,不会改动整个树的结构,所以难度也还行。
LC 450. 删除二叉搜索树中的节点 【略有难度】 ⭐⭐⭐
在 BST 中删除一个节点就比插入要难多了,因为删除可能会发生在树的中间部分,而为了维持 BST 的特性,就涉及到树的结构的较大变动,变动过程可能会出现错误,所以删除的操作就略有难度了。
具体解法可以参考 在 BST 中删除一个数 | labuladong 文章。
该题建议还是自己亲自写一遍。