leetcode
leetcode 451 ~ 500
二叉搜索树的最小绝对差

二叉搜索树的最小绝对差

难度:

标签:

题目描述

给你一个二叉搜索树的根节点 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

 

注意:本题与 783 https://leetcode-cn.com/problems/minimum-distance-between-bst-nodes/ 相同

代码结果

运行时间: 68 ms, 内存: 17.2 MB


/*
 * 题目思路:
 * 1. 先将二叉搜索树中所有节点的值收集到一个列表中。
 * 2. 对列表进行排序,并计算相邻元素之间的最小差值。
 */
 
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.stream.Collectors;
 
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}
 
public class Solution {
    public int minDiffInBST(TreeNode root) {
        List<Integer> values = new ArrayList<>();
        inOrder(root, values);
        Collections.sort(values);
        return values.stream()
                .sorted()
                .collect(Collectors.toList())
                .stream()
                .reduce(Integer.MAX_VALUE, (minDiff, value) -> {
                    if (values.indexOf(value) > 0) {
                        int diff = value - values.get(values.indexOf(value) - 1);
                        minDiff = Math.min(minDiff, diff);
                    }
                    return minDiff;
                });
    }
    
    private void inOrder(TreeNode node, List<Integer> values) {
        if (node == null) return;
        inOrder(node.left, values);
        values.add(node.val);
        inOrder(node.right, values);
    }
}

解释

方法:

这个题解采用了中序遍历二叉搜索树的思路。由于二叉搜索树的中序遍历结果是一个升序序列,所以我们可以在中序遍历的过程中,记录上一个遍历到的节点值 lastVal,并用当前节点值与 lastVal 的差值来更新最小绝对差 minAbs。这样在遍历完整棵树后,minAbs 就是任意两节点差值的最小值。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在中序遍历过程中比较当前节点和上一个节点的值就能得到最小绝对差?
在二叉搜索树(BST)中,中序遍历会按照升序的顺序访问所有节点。因此,相邻两个节点的值之差是所有可能的相邻节点对中差值的最小值。通过比较连续节点的值,我们能够找到整个树中任意两个节点之间的最小绝对差。
🦆
在题解中使用了基于栈的非递归中序遍历方法,这种方法与递归中序遍历相比有哪些优缺点?
基于栈的非递归中序遍历方法与递归方法相比,主要优点是可以避免递归造成的栈溢出,特别是在深度很大的树中。此外,非递归方法的控制流更为明确,有时更易于理解和调试。然而,其缺点包括可能更复杂的编码实现,以及在某些情况下,手动管理栈可能会比自动的函数调用栈更加低效。
🦆
题解假设了最小绝对差的初始值为10^5+1,这个值是如何确定的,是否存在更合理的初始值选择?
这个初始值选择是基于题目对节点值的一般范围假设(例如,节点值可能的最大范围)。这种设定是为了确保在实际的节点值差异计算中,任何实际的差值都会小于这个初始值,从而确保正确更新最小差值。然而,更合理的初始值可以是无穷大(如Python中的float('inf')),这样可以避免对节点值范围的假设,并且使得算法更加通用。
🦆
如果二叉搜索树中包含重复的元素,这种方法是否仍然有效?
严格来说,标准的二叉搜索树不应该包含重复元素,因为这会破坏树的性质。如果二叉搜索树被修改允许重复元素(例如,左子树中的元素严格小于根,右子树中的元素大于等于根),当前算法仍然有效,因为它只关心节点值的差异。然而,如果存在重复元素,最小绝对差可能是0,算法需要能够正确处理这种情况。

相关问题

数组中的 k-diff 数对

给你一个整数数组 nums 和一个整数 k,请你在数组中找出 不同的 k-diff 数对,并返回不同的 k-diff 数对 的数目。

k-diff 数对定义为一个整数对 (nums[i], nums[j]) ,并满足下述全部条件:

  • 0 <= i, j < nums.length
  • i != j
  • |nums[i] - nums[j]| == k

注意|val| 表示 val 的绝对值。

 

示例 1:

输入:nums = [3, 1, 4, 1, 5], k = 2
输出:2
解释:数组中有两个 2-diff 数对, (1, 3) 和 (3, 5)。
尽管数组中有两个 1 ,但我们只应返回不同的数对的数量。

示例 2:

输入:nums = [1, 2, 3, 4, 5], k = 1
输出:4
解释:数组中有四个 1-diff 数对, (1, 2), (2, 3), (3, 4) 和 (4, 5) 。

示例 3:

输入:nums = [1, 3, 1, 5, 4], k = 0
输出:1
解释:数组中只有一个 0-diff 数对,(1, 1) 。

 

提示:

  • 1 <= nums.length <= 104
  • -107 <= nums[i] <= 107
  • 0 <= k <= 107