算法Day16|.二叉树专题五 700.二叉搜索树中的搜索,98.验证二叉搜索树,530.二叉搜索树的最小绝对差,501. 二叉搜索树中的众数

700.二叉搜索树中的搜索

1.题目描述

  • 给定二叉搜索树(BST)的根节点 root 和一个整数值 val。
  • 你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。

2.解题思路 

二叉搜索树是一个有序树:

  • 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 它的左、右子树也分别为二叉搜索树。

3.代码实现

1.确定递归函数的参数和返回值:

        递归函数定义:传入根节点和目标值,返回目标值所在的节点,目标值不存在就返回null。

    //700.二叉搜索树中的搜索
    //递归函数定义:传入根节点和目标值,返回目标值所在的节点,目标值不存在就返回null 
    public TreeNode searchBST(TreeNode root, int val) {}

2.确定终止条件:

        如果为空节点的话,就返回null,表示目标值不存在。

        //递归终止条件
        if (root == null) {
            return root;
        }

 3.确定单层递归的逻辑:

        利用二叉搜索树的特性:

  • 目标值小于当前节点值,去当前节点的左子树寻找。
  • 目标值大于当前节点值,去当前节点的右子树寻找。
  • 目标值等于当前节点值,返回当前节点。
        //单层递归逻辑
        TreeNode res = null;
        if (val < root.val) {
            res = searchBST(root.left, val);//去当前节点的左子树寻找
        } else if (val > root.val) {
            res = searchBST(root.right, val);//去当前节点的右子树寻找
        } else {
            return root;//返回当前节点
        }
        return res;

 完整代码如下:

class Solution {
    //700.二叉搜索树中的搜索
    //递归函数定义:传入根节点和目标值,返回目标值所在的节点,目标值不存在就返回null
    public TreeNode searchBST(TreeNode root, int val) {
        //递归终止条件
        if (root == null) {
            return root;
        }
        //单层递归逻辑
        TreeNode res = null;
        if (val < root.val) {
            res = searchBST(root.left, val);
        } else if (val > root.val) {
            res = searchBST(root.right, val);
        } else {
            return root;
        }
        return res;
    }
}

 98.验证二叉搜索树

1.题目描述

    给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

    有效二叉搜索树定义如下:

  • 节点的左子树只包含 小于 当前节点的数。
  • 节点的右子树只包含 大于 当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

2.解题思路 

要知道中序遍历下,输出的二叉搜索树节点的数值是有序序列。

有了这个特性,验证二叉搜索树,就相当于变成了判断一个序列是不是递增的了。

3.代码实现

3.1递归法

1.确定递归函数的参数和返回值:

        递归函数定义:传入一个节点,采用中序遍历,把节点值放进list中。

     //递归函数定义:传入一个节点,采用中序遍历,把节点值放进list中
    public void travesal(TreeNode root) {}

2.确定终止条件:

        如果为空节点的话,就return。

        //递归终止条件
        if (root == null) {
            return;
        }

 3.确定单层递归的逻辑:

       利用二叉搜索树的特性:

  • 单层递归逻辑(一定采用中序遍历,左中右)

  • 把遍历到的所有节点值放进list 中

  • 将list转换为数组,检查是否有序即可。

        //单层递归逻辑(一定采用中序遍历,左中右)
        isValidBST(root.left);//左
        //把遍历到的所有节点值放进list 中
        inOrderList.add(root.val);
        isValidBST(root.right);//右

完整代码如下:

class Solution {
    //98.验证二叉搜索树
    List<Integer> inOrderList = new ArrayList<>();

    public boolean isValidBST(TreeNode root) {
        travesal(root);
        //将list转换为数组,检查是否有序即可
        int[] inOrderArray = inOrderList.stream()
                           .mapToInt(Integer::intValue).toArray();
        for (int i = 1; i < inOrderArray.length; i++) {
            if (inOrderArray[i] <= inOrderArray[i - 1]) {
                return false;
            }
        }
        return true;
    }

    //递归函数定义:传入一个节点,采用中序遍历,把节点值放进list中
    public void travesal(TreeNode root) {
        //递归终止条件
        if (root == null) {
            return;
        }
        //单层递归逻辑(一定采用中序遍历,左中右)
        isValidBST(root.left);//左
        //把遍历到的所有节点值放进list 中
        inOrderList.add(root.val);
        isValidBST(root.right);//右
    }
}

3.2递归法(双指针)

class Solution {
   //98.验证二叉搜索树(双指针-递归)
    TreeNode pre;
    //递归函数定义:传入一个节点,检查以该节点为根节点的树是不是二叉搜索树
    public boolean isValidBST(TreeNode root) {
        //递归终止条件
        if (root == null) {
            return true;
        }
        //单层递归逻辑(一定采用中序遍历,左中右)
        boolean leftBST = isValidBST(root.left); //左
        //每次比较pre和root的值,只要不满足单调递增就返回false
        if (pre != null && pre.val >= root.val) {
            return false;
        }
        //更新pre,让pre跟在root的后面
        pre = root;                                //中
        boolean rightBST = isValidBST(root.right); //右
        return leftBST && rightBST;
    }
}

530.二叉搜索树的最小绝对差

1.题目描述

给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。

差值是一个正数,其数值等于两值之差的绝对值。

 2.解题思路 

  • 题目中要求在二叉搜索树上任意两节点的差的绝对值的最小值。
  • 注意是二叉搜索树,二叉搜索树可是有序的。
  • 遇到在二叉搜索树上求什么最值啊,差值之类的,就把它想成在一个有序数组上求最值,求差值,这样就简单多了。
  • 当然也可以采用双指针的写法,每次更新差值即可。

 3.代码实现(递归-双指针)

1.确定递归函数的参数和返回值:

        递归函数定义:传入一个节点,用于更新最小绝对差(res)。

    //递归函数定义:传入一个节点,用于更新最小绝对差(res)
    public void travesal2(TreeNode cur) {}

2.确定终止条件:

        如果为空节点的话,就return。

        //递归终止条件
        if (root == null) {
            return;
        }

 3.确定单层递归的逻辑:

       利用二叉搜索树的特性:

  • 单层递归逻辑(一定采用中序遍历,左中右)

  • 每次得到cur和preNode的差值,更新res

  • 更新preNode,让preNode跟在cur的后面

        //单层递归逻辑
        travesal2(cur.left);
        //每次得到cur和preNode的差值,更新res
        if (preNode != null) {
            res = Math.min(res, cur.val - preNode.val);
        }
        //更新preNode,让preNode跟在cur的后面
        preNode = cur;
        travesal2(cur.right);

完整代码如下:

class Solution {
 //530.二叉搜索树的最小绝对差
    int res = Integer.MAX_VALUE;
    TreeNode preNode;

    public int getMinimumDifference(TreeNode root) {
        travesal2(root);
        return res;
    }

    //递归函数定义:传入一个节点,用于更新最小绝对差(res)
    public void travesal2(TreeNode cur) {
        //递归终止条件
        if (cur == null) {
            return;
        }
        //单层递归逻辑
        travesal2(cur.left);
        //每次得到cur和preNode的差值,更新res
        if (preNode != null) {
            res = Math.min(res, cur.val - preNode.val);
        }
        //更新preNode,让preNode跟在cur的后面
        preNode = cur;
        travesal2(cur.right);
    }
}

501. 二叉搜索树中的众数

1.题目描述

        给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有众数(即出现频率最高的元素)。如果树中有不止一个众数,可以按任意顺序返回。

假定 BST 满足如下定义:

  • 结点左子树中所含节点的值 小于等于 当前节点的值
  • 结点右子树中所含节点的值 大于等于 当前节点的值
  • 左子树和右子树都是二叉搜索树

 2.解题思路  

 这道题目呢,递归法从两个维度来讲。

        首先如果不是二叉搜索树的话,应该怎么解题,是二叉搜索树,又应该如何解题,两种方式做一个比较,可以加深大家对二叉树的理解。

3.代码实现

3.1递归法(非二叉搜索树)

  1. 新建一个map,Key:节点值,value:用于存放每个节点出现的频率。
  2. 将map按频率由高到低进行排序,并转换为list。
  3. 得到list中第一个元素(排序后频率最高),添加到结果集中。
  4. 查看是否有和最大频率相同的元素,有的话就加到结果集中,如果不相等,因为排序了,后边的频次都比前边小,终止循环。

 完整代码如下:

class Solution {
    //501. 二叉搜索树中的众数-暴力解法
    //Key:节点值,value:用于存放每个节点出现的频率
    HashMap<Integer, Integer> map = new HashMap<>();

    public int[] findMode(TreeNode root) {
        //结果集
        ArrayList<Integer> ans = new ArrayList<>();
        if (root == null) {
            return ans.stream().mapToInt(Integer::intValue).toArray();
        }
        //得到节点出现的频率map
        travesal4(root);
        //将map按频率由高到低进行排序,并转换为list
        List<Map.Entry<Integer, Integer>> list = map.entrySet().stream()
                .sorted((c1, c2) -> c2.getValue() - c1.getValue())
                .collect(Collectors.toList());
        //得到list中第一个元素(排序后频率最高),添加到结果集中
        ans.add(list.get(0).getKey());
        //查看是否有和最大频率相同的元素,有的话就加到结果集中
        for (int i = 1; i < list.size(); i++) {
            if (list.get(i).getValue() == list.get(0).getValue()) {
                ans.add(list.get(i).getKey());
            } else {
                //如果不相等,因为排序了,后边的频次都比前边小,终止循环
                break;
            }
        }
        return ans.stream().mapToInt(Integer::intValue).toArray();

    }
    public void travesal4(TreeNode cur) {
        //递归终止条件
        if (cur == null) {
            return;
        }
        //单层递归逻辑
        map.put(cur.val, map.getOrDefault(cur.val, 0) + 1);
        travesal4(cur.left);   //左
        travesal4(cur.right);   //右
    }
}

3.2递归法(二叉搜索树)

1.确定递归函数的参数和返回值:

        递归函数定义:传入一个节点,用于更新众数MaxCount,并将众数放进list中

     //递归函数定义:传入一个节点,用于更新众数MaxCount,并将众数放进list中
    public void travesal3(TreeNode cur) {}

2.确定终止条件:

        如果为空节点的话,就return。

        //递归终止条件
        if (root == null) {
            return;
        }

 3.确定单层递归的逻辑:

       利用二叉搜索树的特性:

  1. 单层递归逻辑(一定采用中序遍历,左中右)。

  2. 根据preNode和cur的值,更新count。

  3. 为了只遍历一次,碰到一个count就添加到list中。

  4. count(一个节点出现的个数)大于MaxCount(之前记录的节点最大出现次数),更新MaxCount值​​​​​​​,并将list清空,把MaxCount对应的节点放进list。

  5. 更新preNode,让preNode跟在cur的后面。

        //单层递归逻辑
        travesal3(cur.left);   //左
        //根据preNode和cur的值,更新count
        if (preNode == null) {
            count = 1; //pre不存在,cur为第一个节点,count=1
        } else if (preNode.val == cur.val) {
            count++; //两者相等,count++
        } else {
            count = 1;//两者不相等,新节点出现次数为1
        }
        //为了只遍历一次,碰到一个count就添加到list中
        if (count == MaxCount) {
            list.add(cur.val);
            //count(一个节点出现的个数)大于MaxCount(之前记录的节点最大出现次数)
        } else if (count > MaxCount) {
            MaxCount = count;//更新MaxCount值
            list.clear();//并将list清空
            list.add(cur.val);//把MaxCount对应的节点放进list
        }
        //更新preNode,让preNode跟在cur的后面
        preNode = cur;         //中
        travesal3(cur.right);   //右

 完整代码如下:

class Solution {
     //501. 二叉搜索树中的众数
    TreeNode preNode;
    int count = 0;
    int MaxCount = 0;
    List<Integer> list = new ArrayList<>();

    public int[] findMode(TreeNode root) {
        travesal3(root);
        return list.stream().mapToInt(Integer::intValue).toArray();
    }

    //递归函数定义:传入一个节点,用于更新众数MaxCount,并将众数放进list中
    public void travesal3(TreeNode cur) {
        //递归终止条件
        if (cur == null) {
            return;
        }
        //单层递归逻辑
        travesal3(cur.left);   //左
        //根据preNode和cur的值,更新count
        if (preNode == null) {
            count = 1; //pre不存在,cur为第一个节点,count=1
        } else if (preNode.val == cur.val) {
            count++; //两者相等,count++
        } else {
            count = 1;//两者不相等,新节点出现次数为1
        }
        //为了只遍历一次,碰到一个count就添加到list中
        if (count == MaxCount) {
            list.add(cur.val);
            //count(一个节点出现的个数)大于MaxCount(之前记录的节点最大出现次数)
        } else if (count > MaxCount) {
            MaxCount = count;//更新MaxCount值
            list.clear();//并将list清空
            list.add(cur.val);//把MaxCount对应的节点放进list
        }
        //更新preNode,让preNode跟在cur的后面
        preNode = cur;         //中
        travesal3(cur.right);   //右
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Road_slow

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值