找到范围的交集和重叠并存储结果范围集的最佳算法

时间:2016-07-31 10:02:13

标签: java algorithm redis intersection overlap

我有范围让我们说

  1. 1-10
  2. 20-40
  3. 30-50
  4. 55-65
  5. 65-80
  6. 75-90
  7. 95-100
  8. 如本示例所示,20-40和30-50相交而不是存储两者我需要将其存储为20-50。

    然后我想要55-90而不是55-65,65-80和75-90。

    所以结果集就像这样

    1. 1-10
    2. 20-50
    3. 55-90
    4. 95-100
    5. 我在redis中有这些值,我在Java中存储它们的结构是数组,一个起始数组和一个结束数组。

      我的解决方案:

      for int i =0; i< length-1 ; i++
          for int j=i+1;j<length; j++
              if start[i] <= start[j] && end[i] >= start[j]
                  store the min max in start and end array and remove the other two entries and proceed
      

      我发现这是因为O(n log n)有没有更好的算法来做到这一点?

      Java和redis中的数据结构中的任何建议以及处理此方法的方法或算法都会很棒。

      谢谢

3 个答案:

答案 0 :(得分:1)

使用RangeSet中的Guava

来自文档:

  

选择支持add(Range)操作的实现需要忽略空范围并合并连接的范围。

应用于您的示例:

public static void main(String args[]) {
    final RangeSet<Integer> ranges = TreeRangeSet.create();
    ranges.add(Range.closed(1, 10));
    ranges.add(Range.closed(20, 40));
    ranges.add(Range.closed(30, 50));
    ranges.add(Range.closed(55, 65));
    ranges.add(Range.closed(65, 80));
    ranges.add(Range.closed(75, 90));
    ranges.add(Range.closed(95, 100));

    System.out.println(ranges);
}

输出:

  

[[1‥10],[20‥50],[55‥90],[95‥100]]

作为RangeTreeRangeSet implements Serializable,您可以按原样将它们保存到Redis。

答案 1 :(得分:1)

如果间隔按起始位置排序,则有一种非常简单的线性算法来合并间隔。排序需要O(nlogn),因此总体时间复杂度相同。如果输入没有排序,我相信一般算法仍然需要O(nlogn)。排序通常更快,因为它与一个小常量相关联。这是更有效的解决方案。

这是javascript中的一个实现,只是为了给你一个想法。您可以转换为java或使用node.js运行它:

function merge_intervals(a)
{ // this function save the result IN PLACE
    if (a.length == 0) return;
    var st = a[0][0], en = a[0][1], k = 0;
    for (var i = 1; i < a.length; ++i) {
        if (a[i][0] > en) { // a new interval
            a[k++] = [st, en];
            st = a[i][0], en = a[i][1];
        } else en = a[i][1] > en? a[i][1] : en;
    }
    a[k++] = [st, en]; // add the last interval
    a.length = k; // discard the rest
}

// intervals are half-close-half-open, like C arrays
var a = [[1,10], [20,40], [30,50], [55,65], [65,80], [75,90], [95,100]];
// sort the intervals based on start positions
a.sort(function(x,y) { return x[0]-y[0] });

merge_intverals(a);
for (var i = 0; i < a.length; ++i)
    console.log(a[i].join("\t"));

答案 2 :(得分:0)

我认为范围可能并不总是有序。当然,代码可能不是最好的,但它是功能性的

import java.util.*;


class Interval {
    int lo;
    int hi;
    Interval() {
        lo = 0;
        hi = 0;
    }

    Interval(int lo, int hi) {
        this.lo = lo;
        this.hi = hi;
    }

    @Override
    public String toString() {
        return "[" + lo + "," + hi + "]";
    }
}

public class Demo {
    public static ArrayList<Interval> merge(ArrayList<Interval> list) {
        Collections.sort(list, new Comparator<Interval>() {
            public int compare(Interval i1, Interval i2) {
                if (i1.lo == i2.lo) {
                    return i1.hi - i2.hi;
                }
                return i1.lo - i2.lo;
            }
        });
        System.out.println("Sorted Input: " + list);

        ArrayList<Interval> result = new ArrayList<Interval>();
        Interval prev = list.get(0);
        result.add(prev);
        for (int i = 1; i < list.size(); i++) {
            Interval current = list.get(i);
            if (prev.hi >= current.lo) {
                Interval Interval = new Interval(prev.lo, Math.max(prev.hi, current.hi));
                prev = Interval;
            } else {
                prev = current;
            }
            removeIfExist(result, prev);
            result.add(prev);
        }
        return result;
    }

    private static void removeIfExist(ArrayList<Interval> result, Interval prev) {
        if (result.size() > 0) {
            Interval existing = result.get(result.size() - 1);
            if (existing.lo == prev.lo) {
                result.remove(result.size() - 1);
            }
        }
    }

    public static void main(String[] args) {
        ArrayList<Interval> list = new ArrayList<Interval>();
        System.out.println("--------------------------------------------------------------------------------");
        list.add(new Interval(30, 50));
        list.add(new Interval(20, 40));
        list.add(new Interval(75, 90));
        list.add(new Interval(1, 10));
        list.add(new Interval(95, 100));
        list.add(new Interval(65, 80));
        list.add(new Interval(55, 65));
        System.out.println("Input: " + list);
        System.out.println("merged Interval: " + merge(list));
        System.out.println("--------------------------------------------------------------------------------");

    }
}