二叉搜索树
二叉搜索树简写为BST,Binary search tree,对于其中的每一个节点,该节点的左子树的所有节点值都小于该节点,该节点的右子树的所有节点值都大于该节点,一般二叉搜索树中的节点都是不重复的。对于二叉搜索树上的操作,总体思路还是类似树,递归操作,注意二叉搜索树的特性,以及合理利用二叉搜索树的特性简化操作。
BST添加节点
BST删除节点
在BST中查找结点
验证BST
- 思路1
递归,如果左子树是BST,那么需要root大于左子树最右,如果右子树是BST,那么需要root小于右子树最左。代码看起来有点惨不忍睹。。。不够美观。
代码1:
public class Solution {
public bool IsValidBST(TreeNode root) {
if(root == null) {
return true;
}
if(root.left == null && root.right == null) {
return true;
}
if(root.left != null) {
if(root.left.val >= root.val) {
return false;
}
if(IsValidBST(root.left)) {
var left = root.left;
while(left.right != null) {
left = left.right;
}
if(left.val >= root.val) {
return false;
}
}
else{
return false;
}
}
if(root.right != null) {
if(root.right.val <= root.val) {
return false;
}
if(IsValidBST(root.right)) {
var right = root.right;
while(right.left != null) {
right = right.left;
}
if(right.val <= root.val) {
return false;
}
}
else{
return false;
}
}
return true;
}
}
- 思路2(最简洁)
递归,这次不管他左子树的最大值应该是最右位置还是右子树的最小值应该是最左位置,就直接比较左子树的最大值、右子树的最小值和root,一开始传进去一个一定成立的最值。代码看起来就比较简洁了。
代码2:
public class Solution {
public bool IsValidBST(TreeNode root) {
return IsValid(root, long.MinValue, long.MaxValue);
}
public bool IsValid(TreeNode root, long min, long max) {
if(root == null) {
return true;
}
if(root.val <= min || root.val >= max) {
return false;
}
return IsValid(root.left, min, root.val) && IsValid(root.right, root.val, max);
}
}
- 思路3
BST用中序遍历后应该是一个升序,我们可以在全局变量那块保存一下遍历到的上一个节点,如果当前节点始终比上一个大,那么就是BST无疑了。
代码3:
public class Solution {
TreeNode last;
public bool IsValidBST(TreeNode root) {
if(root == null) {
return true;
}
return IsValid(root);
}
public bool IsValid(TreeNode root) {
if(root.left != null && !IsValid(root.left)) {
return false;
}
if(last == null || last.val < root.val) {
last = root;
}
else {
return false;
}
if(root.right != null && !IsValid(root.right)) {
return false;
}
return true;
}
}
求二叉搜索树中的LCA(最低公共祖先)
- 思路1
想象一下,自己是根节点,站在根节点的位置上眺望,前方是岔路口(左子树右子树),一眼望不到尽头,你的任务是判断p,q最近公共祖先是谁,那么如果p,q分别在前方的一左一右两条路上,那么我就是他们的最近公共祖先,如果我就是p,q中其中一个,那么我还是他们的最近公共祖先,如果p,q都在左边那条路上,那就让他们去看看左儿子是啥情况,同理右边。
代码1:
/**
* Definition for a binary tree node.
* public class TreeNode {
* public int val;
* public TreeNode left;
* public TreeNode right;
* public TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null){
return null;
}
if(root.val == p.val || root.val == q.val){
return root;
}
if(root.val > p.val && root.val < q.val || root.val > q.val && root.val < p.val){
return root;
}
if(root.val > p.val && root.val > q.val){
return LowestCommonAncestor(root.left, p, q);
}
if(root.val < p.val && root.val < q.val){
return LowestCommonAncestor(root.right, p, q);
}
return null;
}
}
- 思路2(最简洁)
这次改进一下,用判断p,q与root的差的相乘结果是否大于零来判断他们是否在同一侧,如果在同一侧,就去这一侧找,直到p,q分别位于root两侧或等于root为止。
代码2:
public class Solution {
public TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null){
return null;
}
while((root.val - p.val) * (root.val - q.val) > 0){
root = root.val > p.val ? root.left : root.right;
}
return root;
}
}