找出 AVL 树中两个数字之间的最小间隙
Posted
技术标签:
【中文标题】找出 AVL 树中两个数字之间的最小间隙【英文标题】:Find the minimum gap between two numbers in an AVL tree 【发布时间】:2012-09-02 01:50:00 【问题描述】:我有一个数据结构作业,除了常规的 AVL 树函数之外,我还必须添加一个函数,该函数返回 AVL 树中任意两个数字之间的最小间隙(AVL 中的节点实际上代表数字。)
假设我们在 AVL 树中有数字(作为节点)1 5 12 20 23 21,该函数应该返回任意两个数字之间的最小间隙。在这种情况下,它应该返回“1”,即 |20-21|或 |21-20|。
应该在 O(1) 内完成。
想了很多,我知道有一个窍门,但就是找不到,我花了好几个小时来解决这个问题。
还有一个任务是找到最大间隙,这很容易,它是最小和最大数之间的差。
【问题讨论】:
为什么最小间隙不是|21 - 20| = 1 ? 哦,非常抱歉!应该是 |21-20|或 |20-21| = 1,函数应该返回 1!非常抱歉这个错误! 当我用这些数字绘制平衡二叉树时,20 是根节点,21 是根的右子树中最深和最左边的叶节点。我有一种感觉,你必须区分根和很深的叶子。我必须再次阅读 AVL 树,看看您是否可以“滥用”这些树的这一特性。 我很确定有这种技巧。令我震惊的是我应该在 O(1) 中做到这一点——我想不出任何算法可以做到这一点!此外我应该提到,AVL 树的所有基本功能,如 Init、Search、Insert、Delete 仍然应该是 O(log(n)) - 所以我确定我不应该在基本功能中添加任何东西!这个问题让我摸不着头脑! 看看这个链接:***.com/questions/1484473/… 似乎确实存在该算法,但需要 O(n) 中的预处理 【参考方案1】:您需要扩展数据结构,否则您无法获得组成树的数字之间的最小间隙的 O(1) 搜索。
你有额外的限制不增加插入/删除/搜索功能的时间复杂度,我假设你也不想增加空间复杂度。
让我们考虑一个通用节点 r,它有一个左子树 r.L 和一个右子树 r.R;我们将扩展节点 r 中的信息附加数字 r.x 定义为以下之间的最小值:
(仅当 r.L 不为空时)r 值和 r.L 上最右边叶子的值 (仅当 r.L 大于 1 时)r.L 根节点的 x 值 (仅当 r.R 不为空时)r 值和 r.R 上最左边的叶子的值 (仅当 r.R 大于 1 时)r.R 根节点的 x 值(如果前面的条件都不是有效的,则为未定义,在叶节点的情况下)
此外,为了快速插入/删除,我们需要在每个内部节点中添加对其最左侧和最右侧叶节点的引用。
你可以看到这些添加:
空间复杂度仅增加一个常数因子 插入/删除函数需要更新 x 值以及每个已更改子树的根的最左边和最右边的叶子,但以不超过 O(log(n)) 的方式实现是微不足道的李> 树根的x值是函数需要返回的值,所以可以O(1)实现树中的最小间隙是根节点的 x 值,更具体地说,对于每个子树,子树元素中的最小间隙仅是子树根 x 价值。
可以通过递归来证明这个陈述: 让我们考虑以节点 r 为根的树,具有左子树 r.L 和右子树 r.R。 归纳假设是 r.L 和 r.R x 值的根是子树的节点值之间的最小间隙的值。 很明显,仅考虑值排序列表中值相邻的节点对就可以找到最小间隙; rL 的节点存储的值形成的对在 rL 根 x 值中具有最小间隙,考虑右子树。鉴于(rL 中的任何节点值)L 根节点的值rR 中的任何节点值),唯一的对不考虑的相邻值有两个:
-
由根节点值和较高的r.L节点值组成的对
根节点值和下r.R节点值组成的对
根据 AVL 树的属性,具有较高值的 r.L 节点是其最右边的叶子,而具有较低值的 r.R 节点是其最左边的叶子。 分配给 rx 值四个值(rL 根 x 值、rR 根 x 值、(r - rL 根) 间隙、(r - rR 根) 间隙)之间的最小值是相同的分配整个树中连续节点值之间的间隙越小,也就是任何可能的节点值对之间的间隙越小。 一个或两个子树为空的情况是微不足道的。 仅由一到三个节点组成的树的基本情况,很容易看出树根的 x 值是最小间隙值。
【讨论】:
我不明白两件事。当我们进行插入时,我们会分配这个字段 (x) 和它的值吗?另外,r 值和 r.L 上最右边叶子的值是什么意思?你的意思是最小的差距是两个数字“r值”和“r.L上最右边的叶子”? 是的,字段“x”占用了额外的空间,但是额外的空间复杂度是 O(n)(每个 n 个节点都有一个 int)并且标准 AVL 树需要 O(n ) 已经,空间复杂度并没有增加(是的,毫无疑问它需要更多空间,但复杂度的顺序是相同的,O(n+n)=O(n))。插入/删除时间复杂度相同:如果添加高达 O(lon(n)) 的计算,则原始 O(lon(n)) 时间复杂度将相同。一个实现肯定会花费更长的时间来执行,但只有一个不变的因素:结构不会失去它的可伸缩性。 x 值在节点插入树时添加,并在需要时通过插入/删除其他节点来更新。是的,我所说的“节点值”是指您从中构建树的数字。 非常棒的方式。谢谢你。但我很好奇,你怎么知道 if (in this condition)->(min gap is between the two values) ?有证据吗? 但有一件事,这个算法并没有告诉我两个数字之间的“最小差距”是多少o.O【参考方案2】:此功能可能对您有所帮助:
int getMinGap(Node N)
int a = Integer.MAX_VALUE ,b = Integer.MAX_VALUE,c = Integer.MAX_VALUE,d = Integer.MAX_VALUE;
if(N.left != null)
a = N.left.minGap;
c = N.key - N.left.max;
if(N.right != null)
b = N.right.minGap;
d = N.right.min - N.key;
int minGap = min(a,min(b,min(c,d)));
return minGap;
这是 Node 数据结构:
class Node
int key, height, num, sum, min, max, minGap;
Node left, right;
Node(int d)
key = d;
height = 1;
num = 1;
sum = d;
min = d;
max = d;
minGap = Integer.MAX_VALUE;
【讨论】:
以上是关于找出 AVL 树中两个数字之间的最小间隙的主要内容,如果未能解决你的问题,请参考以下文章
Fcc找出能被给定的两个参数和参数之间所有连续数字整除的最小公倍数。