我有一个介于0到1000之间的数字线。我在数字行上有许多线段。所有细分市场' x1是> = 0并且所有x2都是< 1000.所有x1和x2都是整数。
我需要找到所有线段的联合。
在此图像中,线段为蓝色,联合为红色:
是否存在针对此类问题的现有算法?
答案 0 :(得分:2)
您可以使用marzullo的算法(有关详细信息,请参阅维基百科)。 这是我写的Python实现:
def ip_ranges_grouping(range_lst):
## Based on Marzullo's algorithm
## Input: list of IP ranges
## Returns a new merged list of IP ranges
table = []
for rng in range_lst:
start,end = rng.split('-')
table.append((ip2int(start),1))
table.append((ip2int(end),-1))
table.sort(key=lambda x: x[0])
for i in range(len(table) - 1):
if((table[i][0] == table[i+1][0]) and ((table[i][1] == -1) and (table[i+1][1] == 1))):
table[i],table[i+1] = table[i+1],table[i]
merged = []
end = count = 0
while (end < len(table)):
start = end
count += table[end][1]
while(count > 0): # upon last index, count == 0 and loop terminates
end += 1
count += table[end][1]
merged.append(int2ip(table[start][0]) + '-' + int2ip(table[end][0]))
end += 1
return merged
答案 1 :(得分:1)
如果未动态更改细分,则这是一个简单的问题。只需按左端对所有段进行排序,然后扫描已排序的元素:
struct Seg {int L,R;};
int cmp(Seg a, Seg b) {return a.L < b.L;}
int union_segs(int n, Seg *segs, Segs *output) {
sort(segs, segs + n, cmp);
int right_most = -1;
int cnt = 0;
for (int i = 0 ; i < n ; i++) {
if (segs[i].L > right_most) {
right_most = segs[i].R;
++cnt;
output[cnt].L = segs[i].L;
output[cnt].R = segs[i].R;
}
if (segs[i].R > right_most) {
right_most = segs[i].R;
output[cnt].R = segs[i].R;
}
}
return cnt+1;
}
时间复杂度为O(nlogn)(排序)+ O(n)(扫描)。
如果动态插入和删除段,并且您希望随时查询并集,则需要一些更复杂的数据结构,例如range tree。
答案 2 :(得分:1)
考虑到段的坐标是有界的([0,1000])整数,您可以使用用零初始化的大小为1000的数组。然后,您将遍历您的一组段,并在该段所覆盖的阵列的每个单元格上设置1。然后,您只需要遍历数组以检查1的连续序列。
--- -----
--- ---
1111100111111100
复杂程度取决于细分的数量,也取决于它们的长度。
这是另一种方法,它也适用于浮点段。对细分进行排序。然后,您只需要遍历已排序的段并比较每个相邻段的边界。如果他们交叉,他们就是同一个联盟。