在数字线上查找线段的联合

时间:2012-09-03 03:21:17

标签: algorithm

我有一个介于0到1000之间的数字线。我在数字行上有许多线段。所有细分市场' x1是> = 0并且所有x2都是< 1000.所有x1和x2都是整数。

我需要找到所有线段的联合。

在此图像中,线段为蓝色,联合为红色:

enter image description here

是否存在针对此类问题的现有算法?

3 个答案:

答案 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

复杂程度取决于细分的数量,也取决于它们的长度。

这是另一种方法,它也适用于浮点段。对细分进行排序。然后,您只需要遍历已排序的段并比较每个相邻段的边界。如果他们交叉,他们就是同一个联盟。