语言:Java/Go
235. 二叉搜索树的最近公共祖先
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
本题是昨天236二叉树最近公共祖先的特定版,单纯求二叉树的时候采用自底向上的回溯法,采用后序遍历。本题指定为二叉搜索树,所以第一时间想到中序遍历是有序的。那么p和q的公共祖先按照特性,值位于p和q中间。因此如果要找到最近的公共祖先,如下面的图所示,节点5位于p和q之间,如果继续向左或向右遍历,则错过了成为p或者q的祖先,因此5就是q和p的最近公共祖先。所以按照从上往下的顺序遍历,第一次遇到数值在p和q之间的,就是最近公共祖先。找到结果就直接返回。
class Solution {
TreeNode traversal(TreeNode node, TreeNode p, TreeNode q){
if(node==null || node.val==p.val||node.val==q.val){
return node;
}
// 让a等于小的值,b等于大的值
int a=p.val, b=q.val;
int c;
if(a>b){
c=a;
a=b;
b=c;
}
if(node.val>=a && node.val<=b) return node;
//向左
if(node.val>b){
TreeNode left=traversal(node.left, p,q);
if (left!=null) return left;
}
//向右
if(node.val<a){
TreeNode right=traversal(node.right,p,q);
if (right!=null) return right;
}
return null;
}
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
return traversal(root, p, q);
}
}
GO:
func traversal(root, p, q *TreeNode)*TreeNode{
//相当于java里的nul
if root==nil || root.Val==p.Val || root.Val==q.Val {
return root
}
var a,b int=p.Val,q.Val
var c int
if a>b{
c=a
a=b
b=c
}
if root.Val>a && root.Val<b{
return root
}
if(root.Val>b){
var left=traversal(root.Left,p,q)
if left!=nil{
return left
}
}
if(root.Val<a){
var right=traversal(root.Right,p,q)
if right!=nil{
return right
}
}
return nil
}
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
return traversal(root,p,q)
}
701.二叉搜索树中的插入操作
给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据保证,新值和原始二叉搜索树中的任意节点值都不同。
注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回任意有效的结果。
本题较简单的一个思路就是,判断待插入的值和根节点的关系,,然后将待插入的元素始终作为叶子节点插入即可。同样注意本题为二叉搜索树,所以不需要遍历整棵树。
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func traversal(root *TreeNode, val int) *TreeNode {
if root==nil {
root=&TreeNode{Val:val} // 创建一个值为val的新节点
return root
}
if root.Val>val{
root.Left=traversal(root.Left,val)
return root
}
if root.Val<val{
root.Right=traversal(root.Right,val)
return root
}
return nil
}
func insertIntoBST(root *TreeNode, val int) *TreeNode {
return traversal(root, val)
}
450.删除二叉搜索树中的节点
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
- 首先找到需要删除的节点;
- 如果找到了,删除它。
本题依然是二叉搜索树,所以要利用好有序的性质进行删除节点的查找,但是找到以后如何进行删除需要仔细。
- 若删除的是叶子节点,则直接删除,返回空为根节点;
- 若删除的是非叶子节点,则还需要将其左右孩子的位置进行重构:
- 如果左孩子为空,右孩子不为空,则需要用右孩子补位,返回右孩子为根节点;
- 如果右孩子为空,左孩子不为空,则需要用左孩子补位,返回左孩子;
- 若左右都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。
class Solution {
TreeNode traversal(TreeNode root, int key){
if(root==null) return root;
if(root.val>key){
root.left=traversal(root.left,key);
return root;
}
if(root.val<key){
root.right=traversal(root.right,key);
return root;
}
//找到值等于key的节点
if(root.val ==key){
//没有左孩子
if(root.left==null) return root.right;
//没有右孩子
else if(root.right==null) return root.left;
//左右孩子均存在
TreeNode cur=root.right;
while(cur.left!=null){
cur=cur.left;
}
cur.left=root.left;
root=root.right;
return root;
}
return null;
}
public TreeNode deleteNode(TreeNode root, int key) {
return traversal(root, key);
}
}
今日心得
这两天完成了对二叉搜索树的增删还有搜索的操作,一定要记住二叉搜索树的特点,不需要遍历整棵二叉树。