235.二叉搜索树的最近公共祖先
题目链接:https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6
解释: 节点 2 和节点 8 的最近公共祖先是 6
思路:
- 有序树,中间节点是p,q的公共祖先,则中间节点在[p, q]的区间内。
- 从上向下去递归遍历,第一次遇到 cur节点是数值在[p, q]区间中,那么cur就是 p和q的最近公共祖先。
- 为什么?说明左子树有p,右子树有q,继续向下遍历会进入一个子树,与另一个点错过。
- 自带方向性,已经告诉了我们下一轮搜索的区间。
方法一:递归法
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 lowestCommonAncestor(root.left, p, q);
}
if (root.val < p.val && root.val < q.val) {
return lowestCommonAncestor(root.right, p, q);
}
return root;
}
}
方法二:迭代法
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
TreeNode curr = root;
while (curr != null) {
if (curr.val > p.val && curr.val > q.val) {
curr = curr.left;
} else if (curr.val < p.val && curr.val < q.val) {
curr = curr.right;
} else {
return curr;
}
}
return null;
}
}
701.二叉搜索树中的插入操作
题目链接:https://leetcode.com/problems/insert-into-a-binary-search-tree
思路:
- 有序遍历BST,但是插入不改变树的结构。
- 理解如何通过递归函数返回值完成了新加入节点的父子关系赋值操作,下一层将加入节点返回,本层用root->left或者root->right将其接住。
递归法
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
if (root == null) {
TreeNode node = new TreeNode(val);
return node;
}
if (val < root.val) {
root.left = insertIntoBST(root.left, val);
}
if (val > root.val) {
root.right = insertIntoBST(root.right, val);
}
return root;
}
}
迭代法
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
if (root == null) return new TreeNode(val);
TreeNode curr = root;
TreeNode pre = null;
while (curr != null) {
pre = curr;
if (val < curr.val) {
curr = curr.left;
} else if (val > curr.val) {
curr = curr.right;
}
}
curr = new TreeNode(val);
if (pre != null) {
if (val < pre.val) {
pre.left = curr;
} else {
pre.right = curr;
}
}
return root;
}
}
450.删除二叉搜索树中的节点
题目链接:https://leetcode.com/problems/delete-node-in-a-bst
Could you solve it with time complexity O(height of tree)?
思路:
通过递归函数的返回值,上一层接住返回的root节点
五种情况
- 第一种情况:没找到删除的节点,遍历到空节点直接返回了
找到删除的节点 - 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
- 第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
- 第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
- 第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if(root == null) return null; // 没找到删除节点,直接返回
if (root.val == key) {
if (root.left == null && root.right == null) {
root = null;
return root;
}
if (root.left != null && root.right == null) {
root = root.left;
return root;
}
if (root.left == null && root.right != null) {
root = root.right;
return root;
}
if (root.left != null && root.right != null) {
TreeNode leftChild = root.left;
TreeNode rightChild = root.right;
TreeNode curr = rightChild;
while (curr.left != null) {
curr = curr.left;
}
root = rightChild;
curr.left = leftChild;
return root;
}
}
if (key < root.val) root.left = deleteNode(root.left, key);
if (key > root.val) root.right = deleteNode(root.right, key);
return root;
}
}
简化
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if (root == null) return null;
if (root.val == key) {
if (root.left == null) return root.right;
if (root.right == null) return root.left;
if (root.left != null && root.right != null){
TreeNode rightChild = root.right;
TreeNode curr = rightChild;
while (curr.left != null) {
curr = curr.left;
}
curr.left = root.left;
root = rightChild;
return root;
}
}
if (root.val > key) root.left = deleteNode(root.left, key);
if (root.val < key) root.right = deleteNode(root.right,key);
return root;
}
}
删除普通二叉树节点:
第一次是和目标节点的右子树最左面节点交换。
第二次直接被NULL覆盖了。