-
235二叉搜索树最近公共祖先
- 代码随想录 (programmercarl.com)
-
第一印象
- 当做普通二叉树的方法是利用后序遍历的回溯机制,返回目标结点。当左右子树返回值都非空时,即为公共祖先,然后递归返回即可。
-
讲解观后感
- 本题利用二叉搜索树的特性主要有两个方便的地方。一是公共祖先一定是在两目标点取值范围内;另一个是最近公共祖先是向下搜索中第一个满足这样取值范围的点。
-
解题代码
- 迭代法
-
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
for root!=nil {
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 root
}
- 递归:
-
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
if (root.Val - p.Val) * (root.Val - q.Val) <= 0 {
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 root
}
-
701二叉搜索树中的插入操作
- 代码随想录 (programmercarl.com)
-
第一印象
- 因为任意插入的方式均可。可以从根节点开始,存储当前结点
root与其父结点pre,根据大小关系向下迭代查找。得到最后一个pre后,根据大小关系进行连接。
-
讲解观后感
- 递归的方式是直接利用指针承接向下查找,遇到空节点之后插入再回到根节点返回值。
-
解题代码
- 迭代
-
func insertIntoBST(root *TreeNode, val int) *TreeNode {
newNode := &TreeNode{Val:val}
if root==nil {
return newNode
}
pre := root
cur := root
for cur!=nil {
if cur.Val>val {
pre = cur
cur = cur.Left
} else if cur.Val<val {
pre = cur
cur = cur.Right
} else {
break
}
}
if pre!=nil && pre.Val > val {
pre.Left = newNode
}
if pre!=nil && pre.Val < val {
pre.Right = newNode
}
return root
}
- 递归
-
func insertIntoBST(root *TreeNode, val int) *TreeNode {
if root == nil {
root = &TreeNode{Val: val}
return root
}
if root.Val > val {
root.Left = insertIntoBST(root.Left, val)
} else {
root.Right = insertIntoBST(root.Right, val)
}
return root
}
-
450删除二叉搜索树中的节点
- 代码随想录 (programmercarl.com)
-
第一印象
- 删除节点后为了保证搜索二叉树的性质,要做很多调整的讨论,具体情况还是在代码中看比较清晰。
-
讲解观后感
- 把二叉搜索树中删除节点遇到的情况总结如下。五种情况:
- 第一种情况:没找到删除的节点,遍历到空节点直接返回了
- 找到删除的节点
- 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
- 第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
- 第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
- 第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。
-
二叉树固用删除方法
- 代码中目标节点(要删除的节点)被操作了两次:
- 第一次是和目标节点的右子树最左面节点交换。
- 第二次直接被NULL覆盖了。
-
解题代码
- 递归
-
func deleteNode(root *TreeNode, key int) *TreeNode {
if root==nil {
return nil
}
if root.Val==key {
if root.Left==nil&&root.Right==nil {
return nil
}
if root.Left==nil || root.Right==nil {
if root.Left==nil {
return root.Right
} else {
return root.Left
}
}
if root.Left!=nil&&root.Right!=nil {
node := root.Left
right := root.Right
for right.Left!=nil {
right = right.Left
}
right.Left = node
return root.Right
}
} else if root.Val < key {
root.Right = deleteNode(root.Right, key)
} else {
root.Left = deleteNode(root.Left, key)
}
return root
}
- 迭代
-
// 迭代版本
func deleteOneNode(target *TreeNode) *TreeNode {
if target == nil {
return target
}
if target.Right == nil {
return target.Left
}
cur := target.Right
for cur.Left != nil {
cur = cur.Left
}
cur.Left = target.Left
return target.Right
}
func deleteNode(root *TreeNode, key int) *TreeNode {
// 特殊情况处理
if root == nil {
return root
}
cur := root
var pre *TreeNode
for cur != nil {
if cur.Val == key {
break
}
pre = cur
if cur.Val > key {
cur = cur.Left
} else {
cur = cur.Right
}
}
if pre == nil {
return deleteOneNode(cur)
}
// pre 要知道是删除左孩子还有右孩子
if pre.Left != nil && pre.Left.Val == key {
pre.Left = deleteOneNode(cur)
}
if pre.Right != nil && pre.Right.Val == key {
pre.Right = deleteOneNode(cur)
}
return root
}