题目描述
给定一个二叉搜索树的根节点root
,返回树中任意两节点的差的最小值。
示例1:
输入: root = [4, 2, 6, 1, 3, null, null]
输出: 1
解释: 注意,root是树节点对象(TreeNode object),而不是数组。给定的树可表示为下图:
最小的差值为1,它是节点1和节点2的差值,也是节点3和节点2的差值。
注意:
- 二叉树的大小范围在
2
到100
; - 二叉树总是有效的,每个节点的值都是整数,且不重复;
- 本题与530题相同;
思路分析
题目难度为简单 ,二叉搜索树的特点为节点坐边的数值均小于本节点值;右子树的值均大于本节点值,这里需要求解任意两节点的差的最小值,我们易知其最小值必出现在相邻节点,故这里直接思考:
- 根节点与左右节点的差值;
- 多个差值之间的比较,得出最小值;
这里需要的就是遍历树,一个节点最多存在两个可比较的值:root.val - root.left.val, root.right.val - root.val
,题干中给出树的高度有限,故我们这里采用简单的递归解法,简单来说就是:
- 判断当前节点是否为空,若为空返回
Integer.MAX_VALUE
; - 判断当前节点的左右节点是否均不存在,若是返回
Integer.MAX_VALUE
; - 返回 当前节点的左右节点差值较小值和左右子树的差值较小值 中的最小值,即为输出;
根据以上思考,我们给出核心的判断代码:
if (root == null || (root.left == null && root.right == null)) {
return Integer.MAX_VALUE;
}
int i1 = root.left == null ? Integer.MAX_VALUE : root.val - root.left.val;
int i2 = root.right == null ? Integer.MAX_VALUE : root.right.val - root.val;
int i3 = solutionRecursive(root.left);
int i4 = solutionRecursive(root.right);
return Math.min(Math.min(i1, i2), Math.min(i3, i4));
上面的写法是为了更好的理解,这里我们进一步简化代码则有:
解题代码
public static int solutionRecursive(TreeNode root) {
if (root == null || (root.left == null && root.right == null)) {
return Integer.MAX_VALUE;
}
return Math.min(Math.min((root.left == null ? Integer.MAX_VALUE
: root.val - root.left.val),
(root.right == null ? Integer.MAX_VALUE
: root.right.val - root.val)),
Math.min(solutionRecursive(root.left),
solutionRecursive(root.right))
);
}
复杂度分析
设n
为树的节点个数,h
为树的高度:
时间复杂度: 这里对每个节点进行了一次访问,时间复杂度为O(n)
;
空间复杂度: 没有借助辅助容器,但是因是递归解法,内存中存在栈空间的使用,故空间复杂度为O(h)
。
小结
在本博客类似的算法文章中提过,树这种数据类型特别适合递归求解,在现实业务场景中,树的出现更多的用在检索需求中,这就使得树的高度不会太高;数据库中甚至想要提高检索效率使用如B树、B+树此类的多叉树来减少I/O,从而提升系统效率和检索速度; 这样的也无需求催生下的树结构,不会太高,这样也为递归这样的算法求解方式提供了一定的适用条件和参考价值。
这里简单说一下适合递归的问题具有的特点:
- 总问题可以细分为若干个有限的小问题,且小问题之间并没有相干性;
- 总问题和小问题的求解方式是相同的;
- 确保递归的函数栈空间不会无限增长或超出题目要求;
Github源码
完整可运行文件请访问GitHub。