用于计算最大数量的子分段的算法

时间:2013-03-06 13:01:22

标签: algorithm

给定n个整数值段的向量,我正在搜索O(n log n)算法来计算包含大多数其他段的段。 事实上,我只对这些细分的数量感兴趣。

我尝试了段树和间隔树的变体,但没有相关的。我的真正问题来自偏序。如果订单是完全的,通过直接计算包含树可以更容易地解决问题。

示例:a = [4;11] b = [2;7] c = [5;8] d = [6;7] e = [3;9] f = [1;10] g = [10;42]

这里我们有f包含e c b和d是最大的。当然,g更长,但不包含任何其他段,所以它不是最大段的问题。

我们可以显示订单图(不显示传递弧):

f -----> b  ---> d
  \-->e--->c-/
       a-/
g

对我来说,主要的问题是我不能排除一段时间处理段,因为在某些时候可能会出现子段,这些子段不包含在f中并构成最大的段。

2 个答案:

答案 0 :(得分:2)

O(n log n)是可能的(我假设开放间隔,没有端点重叠)

您将所有端点排序为排序列表(升序),并跟踪哪个间隔(例如使用id)以及特定点的间隔结束。

现在您维护一个支持以下内容的数据结构:

AppendAtEnd(interval_id)
int GetPosition(interval_id)
Value Remove(interval_id)
IncrementValuesLessThanPosition(j)

这是一个结构,它接受一个键(intervals_ids)并维护它们的有序(按插入时间)列表,并带有一个附加值,该值最初为0,我们用它来跟踪子间隔。 / p>

它允许您在最后插入。使用id删除(并获取相应的值),获取id的位置(如果使用链接列表实现,则将其视为距离头部的距离)并递增列表的特定前缀的所有值。

要将此结构用于我们的问题,我们走上面的排序列表,每次看到间隔的左端点时,我们都会调用AppendAtEnd。

每当我们看到一个区间的右端点时,我们得到它的位置,我们将其移除,并递增所有小于该位置的值(基本上所有具有此移除区间的区间作为子区间)。

使用具有适当装饰信息的平衡树(如子树总和和节点计数),这是可行的,因此每个操作都是O(log n)。

答案 1 :(得分:2)

我在O(n log n)中找到了直接解决方案。

首先使用字典顺序按照x坐标的递增顺序和y坐标的递减顺序对细分进行排序。如果段(a,b)>,则给定此顺序。 (a',b')我们保证a>&gt; a'或a = a'但b < B”。无论哪种方式,(a,b)都不能包含(a',b')。 剩余段的数量是n减去该排序数组中段k的索引。让我们注意那些细分市场。

在这些段中,我们可以使用相反的顺序(减小y然后增加x),并且段k的索引相当于Sk中不包括在段k中的段数。

这里的诀窍是,计算直接包含的段很难,但计数包括段+左侧(或右侧)的非包含段很容易。

总结伪代码:

segments as triples (low,high,id)
orderedXY = sort segments first inc. x then dec. y then inc. id
orderedYX = sort segments first dec. y then inc. x then inc. id
return max(n - orderedXY.find(id=k) - orderedYX.find(id=k) - 1, for every id k)

由于这两种类型,该算法为O(n log n)。

编辑:为了处理重复的段,我们必须对第三个键(段的id)进行排序。这样排序就很稳定了。

编辑':为了确保每个段只计算一次,我们需要减去1。