235. 二叉搜索树的最近公共祖先
思路:
在有序树里,如果判断一个节点的左子树里有p,右子树里有q呢?
因为是有序树,所有 如果 中间节点是 q 和 p 的公共祖先,那么 中节点的数组 一定是在 [p, q]区间的。即 中节点 > p && 中节点 < q 或者 中节点 > q && 中节点 < p。
代码实现
//递归
var lowestCommonAncestor = function (root, p, q) {
const travalTree = (cur, p, q) => {
if (cur === null) return null
if (cur.val > q.val && cur.val > p.val) {
let left = travalTree(cur.left, p, q)
if (left) return left
}
if (cur.val < q.val && cur.val < p.val) {
let right = travalTree(cur.right, p, q)
if (right) return right
}
return cur
}
return travalTree(root, p, q)
};
//迭代
var lowestCommonAncestor = function (root, p, q) {
if (root === null) return null;
let stack = [root];
while (stack.length) {
let cur = stack.pop();
if (cur.val > p.val && cur.val > q.val) {
cur = cur.left
stack.push(cur)
} else if (cur.val < p.val && cur.val < q.val) {
cur = cur.right
stack.push(cur)
} else {
return cur
}
}
};
701.二叉搜索树中的插入操作
思路:
代码实现
function TreeNode (val, left, right) {
this.val = (val === undefined ? 0 : val)
this.left = (left === undefined ? null : left)
this.right = (right === undefined ? null : right)
}
//有返回值的递归写法
var insertIntoBST = function (root, val) {
const setInOrder = (root, val) => {
if (root === null) {
let node = new TreeNode(val);
return node
}
if (root.val > val) {
root.left = setInOrder(root.left, val);
} else if (root.val < val) {
root.right = setInOrder(root.right, val);
}
return root
}
return setInOrder(root, val);
};
//无返回值的递归写法
var insertIntoBST = (root, val) => {
let parent = new TreeNode(0);
const preOrder = (cur, val) => {
if (cur === null) {
let node = new TreeNode(val);
if (parent.val > val) {
parent.left = node
} else {
parent.right = node
}
return
}
parent = cur
if (cur.val > val) {
preOrder(cur.left, val)
}
if (cur.val < val) {
preOrder(cur.right, val)
}
}
if (root === null)
root = new TreeNode(val)
preOrder(root, val)
return root
}
//迭代
var insertIntoBST = (root, val) => {
if (root === null) {
root = new TreeNode(val);
} else {
let parent = new TreeNode(0)
let cur = root;
while (cur) {
parent = cur
if (cur.val > val) {
cur = cur.left
} else {
cur = cur.right
}
}
let node = new TreeNode(val);
if (parent.val > val) {
parent.left = node
} else {
parent.right = node
}
}
return root
}
450.删除二叉搜索树中的节点
思路:
- 第一种情况:没找到删除的节点,遍历到空节点直接返回了
- 找到删除的节点
- 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
- 第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
- 第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
- 第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。
代码实现
var deleteNode = function (root, key) {
if (!root) return null;
if (key > root.val) {
root.right = deleteNode(root.right, key);
return root;
} else if (key < root.val) {
root.left = deleteNode(root.left, key);
return root;
} else {
//叶子节点
if (!root.left && !root.right) {
return null
}
//有一个孩子节点不存在
if (root.left && !root.right) {
return root.left;
} else if (!root.left && root.right) {
return root.right
}
//左右节点都存在
const rightNode = root.right;
//获取最小值节点
const minNode = getMinNode(rightNode)
//将待删除节点的值替换为最小值节点值
root.val = minNode.val;
//删除最小值节点
root.right = deleteNode(root.right, minNode.val)
return root
}
};
function getMinNode (root) {
while (root.left) {
root = root.left
}
return root
}
//迭代
var deleteNode = (root, key) => {
const deleteOneNode = target => {
if (!target) return target
if (!target.right) return target.left;
let cur = target.right
while (cur.left) {
cur = cur.left
}
cur.left = target.left
return target.right
}
if (!root) return root
let cur = root
let pre = null
while (cur) {
if (cur.val === key) break
pre = cur
cur.val > key ? cur = cur.left : cur = cur.right
}
if (!pre) {
return deleteOneNode(cur)
}
if (pre.left && pre.left.val === key) {
pre.left = deleteOneNode(cur)
}
if (pre.right && pre.right.val === key) {
pre.right = deleteOneNode(cur)
}
return root
}
总结
删除二叉搜索树节点的第五种情况不太好理解 继续努力!!