6

我有一个带有整数值的区间列表[例如。[1, 4], [10, 19] 等]。有没有办法将这些间隔放入一些 java 集合的容器中 [例如。设置] 这样我就可以在容器上调用“联合”函数。“联合”函数应该给我一个间隔列表,这样如果任何 2 个插入的间隔重叠,那么它们应该合并到输出中。我尝试在 Guava 中使用 Range 类,但最终在合并之前将所有间隔相互比较。对此的优雅方法将不胜感激!这是我根据下面的回复尝试过的。输出为 [[1, 15], [17, 20]],正确。我想知道是否有一些现有的 API 实现了这样的东西。

public static void main(String[] args) {
    // mock data
    List<MyIntRange> rng_lst = new ArrayList<Junk.MyIntRange>();
    rng_lst.add(new MyIntRange(1, 10));
    rng_lst.add(new MyIntRange(5, 15));
    rng_lst.add(new MyIntRange(17, 20));

    // sort intervals by start position
    Collections.sort(rng_lst);

    // merge the intervals which overlap
    List<MyIntRange> res_lst = new ArrayList<Junk.MyIntRange>();
    MyIntRange old_rng = null;
    for (MyIntRange cur_rng : rng_lst) {
        if (old_rng == null) {
            old_rng = cur_rng;
        } else {
            if (old_rng.rng.upperEndpoint() < cur_rng.rng.lowerEndpoint()) {
                // this does not over lap with the next one
                res_lst.add(old_rng);
                old_rng = cur_rng;
            } else {
                // overlap
                old_rng = new MyIntRange(old_rng.rng.lowerEndpoint(),
                        cur_rng.rng.upperEndpoint());
            }
        }
    }
    // add the last range
    res_lst.add(old_rng);

    // done!
    System.out.println(res_lst);
}

// wrapper around Guava's Range to make it comparable based on the
// interval's start
public static class MyIntRange implements Comparable<MyIntRange> {
    Range<Integer> rng;

    public MyIntRange(int start, int end) {
        rng = Ranges.closed(start, end);
    }

    public int compareTo(MyIntRange that) {
        int res = -1;
        if (this.rng.lowerEndpoint() > that.rng.lowerEndpoint()) {
            res = 1;
        }
        return res;
    }

    public String toString() {
        return "[" + rng.lowerEndpoint() + ", " + rng.upperEndpoint() + "]";
    }
}

谢谢

4

2 回答 2

7

这基本上正是RangeSet刚刚发布的 Guava 14.0 中所做的,除了它为您进行合并,而不是告诉您可以合并哪些范围。

于 2013-03-01T02:33:29.660 回答
3

一个基本算法:

  1. 按开始索引对区间进行排序
  2. 浏览列表。对于第ith 项:
    1. 比较st 项的结束索引i和开始索引。(i+1)
    2. 如果结束索引更大,则将结束索引设置i为的结束索引i+1,并删除该i+1元素。(这将它们合并。)

时间复杂度:O(nlgn),因为初始排序。(也就是说,如果删除操作正确。)

于 2013-03-01T02:17:06.637 回答