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

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


一、题目

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

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

示例 1:

img

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

示例 2:

img

输入: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/ 相同

二、题解
方法一:中序遍历递归

二叉搜索树(BST)是一种特殊的二叉树,其中每个节点的值大于其左子树中的任何节点的值,且小于其右子树中的任何节点的值。由于这个特性,我们可以通过中序遍历BST来获得一个递增的节点值序列。

题目要求计算树中任意两个不同节点值之间的最小差值,我们可以利用中序遍历得到有序的节点值序列,然后在有序序列中找出相邻节点值之间的最小差值。

算法思路:

  1. 初始化一个全局变量 pre,用于在中序遍历中保存前一个节点的值。
  2. 定义一个辅助函数 getMinDiff,该函数用于中序遍历二叉搜索树并计算最小差值。
  3. getMinDiff 函数中,首先递归遍历左子树。
  4. 在遍历当前节点时,计算当前节点值与 pre 节点值的差的绝对值,并将其与之前计算的最小差值比较,更新最小差值。
  5. pre 更新为当前节点。
  6. 最后递归遍历右子树。
  7. 在主函数 getMinimumDifference 中,初始化一个变量 minv 为整型最大值。
  8. minv 的地址传递给 getMinDiff 函数,以便在中序遍历过程中更新最小差值。
  9. 返回最终计算得到的最小差值。

具体实现:

class Solution {
public:
    TreeNode* pre = nullptr; // 用于保存前一个节点
    void getMinDiff(TreeNode* root, int* MinDiff) {
        if (root == nullptr) return;
        getMinDiff(root->left, MinDiff);
        if (pre && fabs(pre->val - root->val) < *MinDiff) {
            *MinDiff = abs(pre->val - root->val);
        }
        pre = root;
        getMinDiff(root->right, MinDiff);
    }
    
    int getMinimumDifference(TreeNode* root) {
        int minv = INT_MAX; // 初始化最小差值为整型最大值
        int* min = &minv; // 获取最小差值的地址
        getMinDiff(root, min); // 调用辅助函数计算最小差值
        return *min; // 返回最小差值
    }
};

算法分析:

  • 时间复杂度:由于我们对每个节点都只访问了一次,且对每个节点的操作是常数时间的,所以整体时间复杂度为 O(N),其中 N 是节点的总数。
  • 空间复杂度:递归过程中使用的空间主要是函数调用栈,最坏情况下需要 O(H) 的空间,其中 H 是树的高度。在平衡二叉搜索树中,H 的平均值为 O(log N),但在最坏情况下可能达到 O(N)。此外,我们还使用了一个常数大小的额外空间来保存 pre 节点。因此,总的空间复杂度为 O(H) 到 O(N)。

当然,还有更方便的写法

class Solution {
public:
    TreeNode* pre = nullptr;
    int minv = INT_MAX;
    void getMinDiff(TreeNode* root) {
        if (root == nullptr) return;
        getMinDiff(root->left);
        if (pre){
            minv = min(abs(pre->val - root->val),minv);
        }
        pre = root;
        getMinDiff(root->right);
    }
    int getMinimumDifference(TreeNode* root) {
        getMinDiff(root);
        return minv;
    }
};
方法二:迭代

算法思路

  • 进行中序遍历,获取有序的节点值序列。
  • 在有序序列中找到相邻节点值之间的最小差值。

具体实现

  • 我们使用栈来进行中序遍历。
  • 初始化栈,当前节点指针 cur 指向根节点,前一个节点指针 pre 初始为 nullptr
  • 初始化一个变量 result 用于记录最小差值,初始值为整型最大值 INT_MAX
  • 进入循环,只要栈不为空或者当前节点不为空:
    • 如果当前节点存在(非空),则将当前节点入栈,并将当前节点指针移动到左子节点,以获取最左边的节点(最小值)。
    • 如果当前节点不存在,说明已经到达了最左边的节点,此时从栈中弹出节点,并进行如下操作:
      • 计算当前节点值与前一个节点值的差,更新 result
      • 更新前一个节点指针 pre 为当前节点。
      • 将当前节点指针移动到右子节点,继续处理右子树。
  • 循环结束后,返回 result 作为结果。
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int getMinimumDifference(TreeNode* root) {
        stack<TreeNode*> st;
        if(root == nullptr) return 0;
        TreeNode *cur = root;
        TreeNode *pre = nullptr;
        int result = INT_MAX;
        while(!st.empty() || cur!= NULL){
            if(cur){
                st.push(cur);
                cur = cur->left;
            }else{
                cur = st.top();
                st.pop();
                if(pre){
                    result = min(cur->val-pre->val, result);
                } 
                pre = cur;
                cur = cur->right;
            }
        }
        return result;
    }
};

算法分析:

  • 时间复杂度:中序遍历需要访问每个节点一次,所以时间复杂度是 O(n),其中 n 是节点数量。
  • 空间复杂度:使用了一个栈来存储节点,所以空间复杂度是 O(h),其中 h 是树的高度。在最坏情况下,树是一条链,h 为 n,但通常情况下 h 远小于 n。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

KeepCoding♪Toby♪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值