235. 二叉搜索树的最近公共祖先
要求: 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
思路
二叉搜索树不纠结于搜索顺序,可以直接从上往下遍历,只要节点的值在[p, q]之间,那么他一定是最近公共祖先 1.递归法
var lowestCommonAncestor = function(root, p, q) {
if(root == null) return root
if(root.val > p.val && root.val > q.val){
let left = lowestCommonAncestor(root.left, p, q)
if(left != null) return left
}else if(root.val < p.val && root.val < q.val){
let right = lowestCommonAncestor(root.right, p, q)
if(right != null) return right
}else {
return root
}
};
//简化
var lowestCommonAncestor = function(root, p, q) {
if(root.val > p.val && root.val > q.val){
return lowestCommonAncestor(root.left, p, q)
}else if(root.val < p.val && root.val < q.val){
return lowestCommonAncestor(root.right, p, q)
}else {
return root
}
};
2.迭代法
while(root){
if(root.val > p.val && root.val > q.val){
root = root.left
}else if(root.val < p.val && root.val < q.val){
root = root.right
}else {
return root
}
}
return null
};
701. 二叉搜索树中的插入操作
要求:给定二叉搜索树(BST)的根节点 root 和要插入树中的值 value ,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。
思路
添加节点不用改变树的结构,本题通过递归函数返回值完成新加入节点的父子关系赋值操作,下一层将加入节点返回,本层用root->left或者root->right将其接住。
var insertIntoBST = function(root, val) {
if(root == null) {
//找到叶子节点 即插入节点的位置了
const node = new TreeNode(val)
return node
}
if(root.val > val){
root.left = insertIntoBST(root.left, val)
}else if(root.val < val){
root.right = insertIntoBST(root.right, val)
}
return root
};
在迭代法遍历的过程中,需要记录一下当前遍历的节点的父节点,这样才能做插入节点的操作。
var insertIntoBST = function(root, val) {
if(root == null){
let node = new TreeNode(val)
return node
}
let cur = root, parent = root
while(cur != null){
parent = cur
if(cur.val > val){
cur = cur.left
}else cur = cur.right
}
let node = new TreeNode(val)
if(val<parent.val) parent.left = node
else parent.right = node
return root
};
450. 删除二叉搜索树中的节点
要求:给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
- 首先找到需要删除的节点;
- 如果找到了,删除它。
思路
本题比较复杂,因为需要改变树的结构;
难点主要是分析二叉搜索树中删除节点遇到的情况:
- 第一种情况:没找到删除的节点,那么遍历到空节点直接返回;
- 找到删除的节点
- 第二种情况:左右孩子都为空(即叶子节点),直接删除节点,返回null
- 第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
- 第四种情况:删除节点的左孩子不为空,右孩子为空,删除节点,左孩子补位,返回左孩子为根节点
- 第五种情况:删除节点的左、右孩子都不为空,应该将删除节点的左子树放到删除节点的右子树最左侧的节点下面
var deleteNode = function(root, key) {
if(root == null) return null
if(root.val == key){
if(root.left == null && root.right == null) return null
else if(root.left != null && root.right == null) return root.left
else if(root.left == null && root.right != null) return root.right
else {
let cur = root.right //指向删除节点的右子树
while(cur.left != null) cur=cur.left //这样才能找到右子树下面最小的数
cur.left = root.left
return root.right
}
}
if(key < root.val) root.left = deleteNode(root.left, key)
if(key > root.val) root.right = deleteNode(root.right, key)
return root
};