题目介绍
力扣530题:leetcode-cn.com/problems/mi…
方法:中序遍历
考虑对升序数组 a 求任意两个元素之差的绝对值的最小值,答案一定为相邻两个元素之差的最小值,即
其中 n 为数组 a 的长度。其他任意间隔距离大于等于2的下标对 (i,j)的元素之差一定大于下标对 (i,i+1)的元素之差,故不需要再被考虑。
回到本题,本题要求二叉搜索树任意两节点差的绝对值的最小值,而我们知道二叉搜索树有个性质为二叉搜索树中序遍历得到的值序列是递增有序的,因此我们只要得到中序遍历后的值序列即能用上文提及的方法来解决。
二叉树的中序遍历有多种方式,包括递归、栈、Morris 遍历等,读者可选择自己最擅长的来实现。下文代码提供最普遍的递归方法来实现,
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
List<Integer> data = new ArrayList<>();
int min = Integer.MAX_VALUE;
public int getMinimumDifference(TreeNode root) {
inOrder(root);
for(int i = 0; i < data.size(); i++) {
for(int j = i + 1 ; j < data.size() ; j++) {
if ((data.get(j) - data.get(i)) <= min) {
min = data.get(j) - data.get(i);
}
}
}
return min;
}
public void inOrder(TreeNode root) {
if(root == null) {
return;
}
inOrder(root.left);
data.add(root.val);
inOrder(root.right);
}
}
但是上述代码的时间复杂度为O(N^2),不是很理想。朴素的方法是经过一次中序遍历将值保存在一个数组中再进行遍历求解,我们也可以在中序遍历的过程中用 pre 变量保存前驱节点的值,这样即能边遍历边更新答案,不再需要显式创建集合来保存,需要注意的是 pre 的初始值需要设置成任意负数标记开头,下文代码中设置为 -1。修改代码如下:
class Solution {
int pre;
int ans;
public int getMinimumDifference(TreeNode root) {
ans = Integer.MAX_VALUE;
pre = -1;
dfs(root);
return ans;
}
public void dfs(TreeNode root) {
if (root == null) {
return;
}
dfs(root.left);
if (pre == -1) {
pre = root.val;
} else {
//更新元素差最小绝对值
ans = Math.min(ans, root.val - pre);
pre = root.val;
}
dfs(root.right);
}
}
复杂度分析
-
时间复杂度:O(n),其中 nn 为二叉搜索树节点的个数。每个节点在中序遍历中都会被访问一次且只会被访问一次,因此总时间复杂度为 O(n)。
-
空间复杂度:O(n)。递归函数的空间复杂度取决于递归的栈深度,而栈深度在二叉搜索树为一条链的情况下会达到 O(n)级别。