当前位置: 首页 > article >正文

代码随想录刷题笔记 DAY 21 | 二叉搜索树的最小绝对值差值 No.530 | 二叉搜索树中的众数 No.501 | 二叉树的最近公共祖先 No.236

Day 21

01. 二叉搜索树的最小绝对值差值(No. 530)

题目链接

代码随想录题解

1.1 题目

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

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

示例 1:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

输入:root = [4,2,6,1,3]
输出:1

示例 2:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

输入:root = [1,0,48,null,null,12,49]
输出:1

提示:

  • 树中节点的数目范围是 [2, 104]
  • 0 <= Node.val <= 105
1.2 笔记

提到二叉搜索树其解题最重要的特质就是:

中序遍历的时候输出是一个有序的序列

那本题中的问题就比较简单了,转化为一个 有序序列 的差的绝对值的最小值,这个最小值一定是 出现在相邻的位置,因为前一个减去后一个的绝对值肯定不可能小于前一个减去后面其他的值。

先思考如何在数组中实现这个算法,再将其转化为二叉树递归的写法:

因为要同时操作两个数,所以需要一个指针指向前一个值,很容易可以写出代码:

public static void getMin(int[] arr) {
    int pre = -1; // 指针,指向前一个值
    int res = Integer.MAX_VALUE;
    for (int i : arr) {
        if (pre == -1) {
            i = pre; // 为 pre 初始化
        } else {
            res = Math.min(res, i - pre);
            pre = i;
        }
    }	
}

这样不断遍历直到结束就能得到查的最小绝对值。

接下来就是将其改为二叉树的写法,已知中序遍历得到的结果其实就是该数组,所以将上面的步骤直接搬到中序位置即可。

1.3 代码
class Solution {
    int pre;
    int ans;
    public int getMinimumDifference(TreeNode root) {
        pre = -1;
        ans = Integer.MAX_VALUE;
        reverse(root);
        return ans;
    }
    public void reverse(TreeNode node) {
        if (node == null) {
            return;
        }
        reverse(node.left);
        if (pre == -1) {
            pre = node.val;
        } else {
            ans = Math.min(ans, node.val - pre);
            pre = node.val;
        }
        reverse(node.right);
    }
}

02. 二叉搜索树中的众数(No. 501)

题目链接

代码随想录题解

2.1 题目

给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。

如果树中有不止一个众数,可以按 任意顺序 返回。

假定 BST 满足如下定义:

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

示例 1:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

输入:root = [1,null,2,2]
输出:[2]

示例 2:

输入:root = [0]
输出:[0]

提示:

  • 树中节点的数目在范围 [1, 104]
  • -105 <= Node.val <= 105
2.2 笔记

还是和上面相同,对于二叉搜索树优先考虑对数组的操作,然后将这个操作转换到二叉树的中序遍历即可。

对于一个有序数组要求众数的话,首先需要一个指针指向前一个数,还需要一个 tempNum 来统计当前的总数和一个 maxNum 来统计总的数目,当
current == pre 的时候就让 tempNum++,且当 current != pre 的时候说明已经到了不同的数字,再去统计 tempNummaxNum 哪个大,持续遍历更新直到遍历结束。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

直接写出代码

maxNum = 0;
tempNum = 0;
List<Integer> res = new ArrayList<>();
pre = Integer.MAX_VALUE;

for (int current : arr) {
    if (pre == Integer.MAX_VALUE || current != pre) {
    	tempNum = 1;
    	pre = current;
    } else {
    	tempNum++;
    }
    if (tempNum > maxNum) {
    	res.clear();
    	res.add(node.val);
    	maxNum = tempNum;
    } else if (tempNum == maxNum) {
    	res.add(node.val);
    }
}

注意当 tempNum > maxNum 的时候说明此时 res 中存储的内容已经不是最大的了,这时候就需要 res.clear() 来清除内部的值再来添加。

最后将这段代码转移到中序遍历中即可。

2.3 代码
class Solution {
    int pre = Integer.MAX_VALUE; // 前一个节点的值
    List<Integer> res = new ArrayList<>(); // 结果集
    int maxNum; //最大值
    int tempNum; // 当前节点的总数
    public int[] findMode(TreeNode root) {
        maxNum = 0;
        tempNum = 0;
        reverse(root);
        int[] resArr = new int[res.size()];
        for (int i = 0; i < res.size(); i++) {
            resArr[i] = res.get(i);
        }
        return resArr;
    }
    public void reverse(TreeNode node) {
        if (node == null) {
            return;
        }
        
        reverse(node.left);
        
        // 计数
        if (pre == Integer.MAX_VALUE || node.val != pre) {
            tempNum = 1;
            pre = node.val;
        } else {
            tempNum++;
        }
        // 判断
        if (tempNum > maxNum) {
            res.clear();
            res.add(node.val);
            maxNum = tempNum;
        } else if (tempNum == maxNum) {
            res.add(node.val);
        }
        
        reverse(node.right);
    }
}

03. 二叉树的最近公共祖先(No. 236)

题目链接

代码随想录题解

3.1 题目

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

示例 1:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。

示例 2:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。

示例 3:

输入:root = [1,2], p = 1, q = 2
输出:1

提示:

  • 树中节点数目在范围 [2, 105] 内。
  • -109 <= Node.val <= 109
  • 所有 Node.val 互不相同
  • p != q
  • pq 均存在于给定的二叉树中。
3.2 笔记

要找到最近的公共祖先,首先想到的思路是这样的:

先找到 p 点或者 q 点,不断向上返回,直到双方的遍历的节点重合,则就说明找到了最近的公共祖先。

两边节点重合就代表着:

这个节点的左子树含有 p 或者 q 其中之一,右子树含有 p 或者 q 其中之一

能够得出这个结论是因为题目中要求的 最近,如果这个节点的左子树或者右子树包含 p 和 q 那它一定不是最近的公共祖先,且题目中提到每个节点的 val 不重复,且一定会包含 p 和 q,由此推断出如上的结论。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可以通过 Boolean 来判断是否含有,然后在 left == true && right == true 的时候读取这个节点然后返回;比如上图中,遍历到 2 的时候发现其左子树和右子树不分别包含 p q,说明 2 不是需要的节点,当遍历到 5 的时候,发现其 左子树和右子树分别包含 p 和 q 所以返回 5,需要注意的是针对与题目中的实例 2 ,也就是 p 或者 q 就是它们的公共祖先的情况要做额外的处理。

这里因为题目中要求的是返回 TreeNode 所以这里将返回值设为 TreeNode,返回值设定为 p 和 q 的公共祖先,以 left 和 right 是否为空作为判断依据来判断是否左子树和右子树同时包含:

    if (node == null) {
    	return null;
    }
    if (node.val == pVal || node.val == qVal) {
    	return node;
    }
    TreeNode left = reverse(node.left);
    TreeNode right = reverse(node.right);
	// 判断逻辑

if (left != null && right != null) 说明此时是需要的节点,其判断方法和上面的思想是完全相同的。

但好处是不需要处理 p 或者 q 就是它们的公共祖先的情况

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因为上面的代码当遇到 q = 2 的时候就通过
if (node.val == pVal || node.val == qVal) {return node;} 来直接返回了,这样直到顶上返回的值都是 2

而如果采用刚刚的情况就需要再多加一步来判断这个情况

3.3 代码
class Solution {
    int pVal;
    int qVal;
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        pVal = p.val;
        qVal = q.val;
        return reverse(root);
    }
    public TreeNode reverse(TreeNode node) {
        if (node == null) {
            return null;
        }
        if (node.val == pVal || node.val == qVal) {
            return node;
        }
        TreeNode left = reverse(node.left);
        TreeNode right = reverse(node.right);
        if (left != null && right != null) {
            return node;
        } else if (left == null && right != null) {
            return right;
        } else if (left != null && right == null) {
            return left;
        } else {
            return null;
        }
        
    }
}

http://www.kler.cn/a/227635.html

相关文章:

  • 全自动网页生成系统重构版源码
  • Cox等级资料是个坑
  • 九、开发进度月报
  • React从 EMAScript5编程规范到 EMAScript6编程规范过程中的几点改变
  • 使用最大边界相关算法处理文章自动摘要
  • 自动驾驶:Apollo如何塑造人类的未来出行
  • pgsql中in 和 join 怎么选
  • 缓存的概念
  • 【QT+QGIS跨平台编译】之二十一:【freetype+Qt跨平台编译】(一套代码、一套框架,跨平台编译)
  • 记录首次使用yolov8-obb
  • week03day03(文件操作、正则表达式1)
  • 【C++入门学习指南】:函数重载提升代码清晰度与灵活性
  • 小程序中封装下拉选择框
  • 从传统到现代:易点易动固定资产管理系统利用RFID技术高效管理固定资产
  • 以太网-环回地址
  • 风险管理和采购管理核心考点梳理
  • go使用gopprof分析内存泄露
  • 汽车租赁系统
  • IP地址查询网络威胁:解析威胁、防范攻击
  • DS:时间复杂度和空间复杂度