Range minimum & Lowest common ancestors

本文探讨了在静态数组上实现高效的空间使用与快速查询的方法,包括预处理技术、使用二叉树结构、以及利用笛卡尔树解决范围最小值问题和最低公共祖先问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

If we can solve one of these two problems in space S(n) and query time Q(n), then the same is true for the other problem.

We can solve the two problems with O(n log n) space and O(1) query time (fairly easy)

We can solve the two problems with O(n) space and O(1) query time (more complicated)

Range Minimum

给一个静态数组A,找到i到j范围内的最小值或它的index,并且在有多个最小值的情况下依然能正确判断。

一些可行方案:

  1. Just store the array A without preprocessing. Compute query(i,j) each time.正常储存查找
    • O(n) space for array A (O(1) extra space, so in-place)
    • O(n) query time
  2. Build table T[i, j] storing query(i,j)将每一个范围的值存放在一个二位数组中。
    • O(n^2) space
    • O(1) query time
  3. Range query solution from last time: Binary tree, elements of A are leaves, each internal node stores minimum of its two children query(i,j) is double binary search每次都进行range query。
    • O(n) space
    • O(log n) query time

O(n log n) space, O(1) query time

如果两个区间重合,可以通过搜索两个区间的最小值再比较来代大的区间的最小值。
- Store a subset of the precomputed T(i, j)
- Make the subset big enough that every possible range is the union of two overlapping ranges for which we have precomputed the result
存在U[i,k]中,用k表示区间长度,k最大到log2n⌊log2n⌋, 用i表示开始位置,往后k个位置的最小值。

查询时,很直接
k=log2(ji+1)k=⌊log2(j−i+1)⌋
计算区间长度,不够再加
return min(U[I,k],U[j2k+1,k)(U[I,k],U[j−2k+1,k)

Query time is O(1)
construct time O(n log n) time, O(n log n) space

Lowest Common Ancestors

Two applications of Lowest Common Ancestor (LCA) problem
1. Distances in trees
2. Bandwidth queries in tree network
The second application leads us into
I Cartesian trees
I Connection between Range Minimum and LCA.

Calculating Distances in trees

distance(x,y) = depth(x) + depth(y) − 2 · depth(LCA(x, y))

Bandwidth in Tree Networks

给一棵为确定根的树N代表一个网络,每条边有bandwith
Given two network nodes x and y, bandwidth(x,y) is the minimum bandwidth on the path between x and y.
如何快速找到最小bandwidth?使用Cartesian Tree

Cartesian Tree

笛卡尔树

一个序列的笛卡尔树有这样的性质:
- 笛卡尔树的中序遍历产生序列
- 树是堆排序的
一个例子就是树堆

笛卡尔树的叶子节点是网络的节点
根结点是最小权重的边。
内部节点是网络的边。
随意那边是左孩子,哪边是右孩子。

为了找到x and y的minimum bandwidth,
1. 找到cartesian tree的叶子
2. 找到他们的公共祖先。

构建笛卡尔树,不断拿出网络中的最小权重的边,分成左右两棵子树,递归操作。

Using LCA to solve Range Minimum

将range minimum使用Cartesian tree转化为LCA问题。
1.存储点对(value,position)
2.根为最小值,字典顺序,左边优先
3.递归左右子树
4.此时的RangeMinx(x,y)变为找x,y的最小公共祖先。

构建
查找

Using Range Minimum to solve LCA

给一棵树,
1. 给每一条边分配到root的距离
2. 前序遍历树,注意回溯的情况也要存,将点对存储在数组中
3. LCA(x, y) 即为RangeMin(firstindex(x),firstindex(y))

以下是C#中二叉树的lowest common ancestor的源代码: ```csharp using System; public class Node { public int value; public Node left; public Node right; public Node(int value) { this.value = value; this.left = null; this.right = null; } } public class BinaryTree { public Node root; public BinaryTree() { this.root = null; } public Node LowestCommonAncestor(Node node, int value1, int value2) { if (node == null) { return null; } if (node.value == value1 || node.value == value2) { return node; } Node left = LowestCommonAncestor(node.left, value1, value2); Node right = LowestCommonAncestor(node.right, value1, value2); if (left != null && right != null) { return node; } return (left != null) ? left : right; } } public class Program { public static void Main() { BinaryTree tree = new BinaryTree(); tree.root = new Node(1); tree.root.left = new Node(2); tree.root.right = new Node(3); tree.root.left.left = new Node(4); tree.root.left.right = new Node(5); tree.root.right.left = new Node(6); tree.root.right.right = new Node(7); Node lca = tree.LowestCommonAncestor(tree.root, 4, 5); Console.WriteLine("Lowest Common Ancestor of 4 and 5: " + lca.value); lca = tree.LowestCommonAncestor(tree.root, 4, 6); Console.WriteLine("Lowest Common Ancestor of 4 and 6: " + lca.value); lca = tree.LowestCommonAncestor(tree.root, 3, 4); Console.WriteLine("Lowest Common Ancestor of 3 and 4: " + lca.value); lca = tree.LowestCommonAncestor(tree.root, 2, 4); Console.WriteLine("Lowest Common Ancestor of 2 and 4: " + lca.value); } } ``` 在上面的代码中,我们定义了一个Node类和一个BinaryTree类。我们使用BinaryTree类来创建二叉树,并实现了一个LowestCommonAncestor方法来计算二叉树中给定两个节点的最近公共祖先。 在LowestCommonAncestor方法中,我们首先检查给定节点是否为null或与给定值之一匹配。如果是,则返回该节点。否则,我们递归地在左子树和右子树上调用LowestCommonAncestor方法,并检查它们的返回值。如果左子树和右子树的返回值都不为null,则当前节点是它们的最近公共祖先。否则,我们返回非null的那个子树的返回值。 在Main方法中,我们创建了一个二叉树,并测试了LowestCommonAncestor方法的几个不同输入。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值