Algorithm 最大相交间隔
我手头有以下任务。我得到了N条规则,每个规则由3个区间组成 A1 B1 C1 D1 E1 F1Algorithm 最大相交间隔,algorithm,data-structures,Algorithm,Data Structures,我手头有以下任务。我得到了N条规则,每个规则由3个区间组成 A1 B1 C1 D1 E1 F1 A2 B2 C2 D2 E2 F2 A3 B3 C3 D3 E3 F3 . . . 一个Bn Cn Dn En Fn 每个规则由三个不同的间隔组成[a、b][c、d][e、f] 让我们考虑包含三个值x、y和z的输入。如果a相交不是传递关系,则该输入将满足一个规则:如果a=[0,2],B=[1,3],C=[2,4],(a,B)和(B,C)相交,但不是(a,C)。所以答案是,一个点最多可以位于一个区
A2 B2 C2 D2 E2 F2
A3 B3 C3 D3 E3 F3
.
.
.
一个Bn Cn Dn En Fn
每个规则由三个不同的间隔组成[a、b][c、d][e、f]
让我们考虑包含三个值x、y和z的输入。如果a相交不是传递关系,则该输入将满足一个规则:如果a=[0,2],B=[1,3],C=[2,4],(a,B)和(B,C)相交,但不是(a,C)。所以答案是,一个点最多可以位于一个区间,即使B与两个相交
一个合适的暴力解决方案是计算规则所有子集的交集,并选择交集不为零的最大子集。但那将按O(2^N)的比例缩放顺便说一句,这个问题被称为最大间隔刺伤问题(或其变体)。你可以在谷歌上找到它的参考。你的方法是无效的,因为当规则1与规则2相交,规则1与规则3相交时,这并不意味着规则2与规则3相交 例如:
Rule1: [1,2] [3,4] [5,6]
Rule2: [1,1] [3,3] [5,5]
Rule3: [2,2] [4,4] [6,6]
在您的解决方案中,当您修复外部循环中的规则1时,然后在嵌套循环中查找规则2和规则3,并得到3的结果,而正确答案是2
我有一个可行的解决方案,但不是很有效:O(K3*N),其中K来自规则区间的定义域(K=max\u interval\u value-min\u interval\u value),N是规则的数量。它还消耗O(K*N)内存。如果这个设置符合问题的时间和内存限制,我可以描述我的解决方案,如果不是,我宁愿不要浪费时间
更新:
好了,开始吧。为简单起见,我将假设规则中出现的最小数是0,最大数是K。因此,只有K+1个可能的整数可以满足至少一个规则的间隔
由于每个规则正好有三个间隔,因此必须创建三个与这些间隔相对应的数组。索引i
处的数组元素将包含一组规则,这些规则在相应的间隔中包括numberi
。每个数组的长度为K+1
例如,如果我们有规则:
A: [1,2][3,4][5,6]
B: [1,1][2,2][6,6]
C: [2,2][4,4][5,5]
然后,第一个数组(对应于位置1处的间隔)将是:
第二个数组对应于第二个位置的间隔:
0:{}, 1:{}, 2:{B}, 3:{A}, 4:{A, C}, 5:{}, 6:{}
第三个阵列将是:
...all empty... 5: {A, C}, 6: {A, B}
现在了解如何填充这些数组。从每个元素中的空集开始。然后你要遵守所有规则。对于每个规则,您将遍历位于相应间隔中的所有值,并将当前规则添加到适当的集合中。例如,对于第一个间隔的规则A
,您需要迭代值1,2,并将A
添加到索引1,2处的第一个数组中。这部分需要3*K*N个步骤(假设将元素添加到集合中是O(1))
接下来要做的基本上是尝试找出一个能够满足大多数规则的输入。您需要三个嵌套循环,例如,第一个间隔为i
,第二个间隔为j
,第三个间隔为k
。您需要迭代从0到K的所有可能值。对于i,j,K的每个组合,您需要与三个集合相交,每个集合取自相应的数组。回到这个例子,对于i=2,j=4,k=5,你需要将{A,C}与{A,C}与{A,C}相交,这将得到最大的规则集。对于i=1,j=3,k=5,你将把{A,B}与{A}和{A,C}相交,只得到{A}。所以,您需要迭代,计算交集并找到最大的规则集。这部分的复杂性是O(K3*N),其中K3来自嵌套循环,N是集合交集的代价
就这些。我没有对这个解决方案考虑太多,所以可能它可以进一步优化。但至少它是多项式
更新
现在,如何消除一个嵌套循环
当您有一些i
和j
并且已经计算了前两个数组的组的交集时,您实际上得到了一个新任务。现在你们有了一组组,你们需要找到这个集合的最大子集,它只满足一个剩余的区间(第三个区间)。我建议迭代从0到K的所有可能值,并为每个值维护由该值满足的组集。为了做到这一点,您必须以两种方式对组的初始子集进行排序,第一种是按第一个区间的边界排序,第二种是按第二个区间的边界排序。让我们调用第一个排序数组添加顺序
,第二个删除顺序
。(稍后您会看到,为了简单起见,这些数组可以被队列替换)
如果初始子集中有三个组:
A: [..][..][2,4]
B: [..][..][2,2]
C: [..][..][1,3]
它们的顺序如下:C、A、B用于添加顺序
C: [..][..][1,3]
A: [..][..][2,4]
B: [..][..][2,2]
B,C,A用于删除订单
:
B: [..][..][2,2]
C: [..][..][1,3]
A: [..][..][2,4]
循环中需要三个指针。第一个(g\u add
)将指向(数组中的add\u order
)您将要“添加”到维护集的组,第二个(g\u remove
)将指向(数组中的remove\u order
)您将要从维护集中删除的组。最后,k
将保存当前值(从0到k)
返回示例,您将从0到5迭代k
(g_add
和g_remove
最初指向对应数组的第一组):
如前所述,可以考虑<代码>删除命令>代码>代码> AddioOrthOuts<代码>作为队列,它们的头将相应地添加和删除候选。 现在谈谈复杂性。迭代所有对的
i
和j
取O(K2)。现在,对于每一对这样的集合,你不需要对组进行排序,因为这可以在循环开始之前的一开始就完成。然后需要迭代k
,添加和删除组。因为每个组只处理两次(添加和删除时),并且k
是无效的
B: [..][..][2,2]
C: [..][..][1,3]
A: [..][..][2,4]
k=0, g_add=C, g_remove=B, res={} // nothing to do
k=1, g_add=C, g_remove=B, res={} // `g_add` is pointing on the group whose first boundary is less or equal to `k`, adding this group to set of current groups, and incrementing `g_add`
k=1, g_add=A, g_remove=B, res={C} // moving on, incrementing `k`
k=2, g_add=A, g_remove=B, res={C} // now A satisfies adding condition
k=2, g_add=B, g_remove=B, res={C, A} // B satisfies adding condition too
k=2, g_add=, g_remove=B, res={C, A, B} // incrementing k (note that at that point we have largest set)
k=3, g_add=, g_remove=B, res={C, A, B} // B has second boundary less than k, removing
k=3, g_add=, g_remove=C, res={C, A} // B has second boundary less than k, removing
k=3, g_add=, g_remove=C, res={C, A} // k++
k=4, g_add=, g_remove=C, res={C, A} // C is suitable for removing
k=4, g_add=, g_remove=A, res={A} // k++
k=5, g_add=, g_remove=A, res={A} // A is suitable for removing
k=5, g_add=, g_remove=, res={} // we are done
1,x,x,x,x,x
5,x,x,x,x,x
3,x,x,x,x,x
A_val = [ 1,5,3 ];
A_rule = [ 0, 1, 2 ];
A_val = [ 1,3,5 ];
A_rule = [ 0, 2, 1 ];
5,8,x,x,x,x
1,3,x,x,x,x
7,10,x,x,x,x
6,9,x,x,x,x
1,3,x,x,x,x
5,6,x,x,x,x
7,10,x,x,x,x
6,9,x,x,x,x
6,8,x,x,x,x