проблема разделения диапазона - PullRequest
4 голосов
/ 01 декабря 2010

люди

слышал об этой проблеме довольно давно. подумал о том, чтобы опубликовать его, чтобы получить некоторые представления о том, как это сделать, используя какую-то конструкцию или другие эффективные средства (могут быть специализированные деревья)

Учитывая набор диапазонов в парах (5,18) (12,23) (15,30)

разбить их на все возможные поддиапазоны, которые, как видно, перекрывают другие диапазоны в наборе. лайк (5,11) (12,14) (15,18) (19,23) (24,30)

спасибо всем, ценю это ...

раджан ...

PS это стандартная проблема, если да, то хотел бы, чтобы вы знали ее имя

Ответы [ 3 ]

5 голосов
/ 01 декабря 2010

Добавьте все конечные точки диапазона в список, но отметьте их как начальные / конечные точки.

[(5, S), (18, E), (12, S), (23, E), (15, S), (30, E)]

Сортируйте их по позиции, разрывая связи, помещая начальные точки перед конечными точками.

[(5, S), (12, S), (15, S), (18, E), (23, E), (30, E)]

Затем вы можете определить диапазоны, перебирая этот список, отслеживая, сколько начальных и конечных точек мы обработали до сих пор. Если мы видим начальную точку, это начало нового диапазона для вывода. Если наш счет положительный, мы должны сначала закончить текущий диапазон. Если мы видим конечную точку, конец текущего диапазона.

1 голос
/ 11 июля 2013

Может быть, я что-то упустил, но это кажется простым решением: Бросьте все числа в контейнер набора C ++ STL. Они будут автоматически упорядочены в порядке возрастания. поэтому они будут читать следующим образом: 5,12,15,18,23,30 Так что, если вы можете терпеть перекрытие, то: (5,12) (12,15) (15,18), (18,23) (23,30) - это диапазоны, которые строятся путем повторения каждого числа дважды, ожидают первое и последнее, а затем группируют два числа.

Если вы не можете допустить перекрытия, диапазоны можно построить, поместив увеличенное число в список вместо его повторения.

1 голос
/ 19 июня 2012

Ладно, после некоторой переделки я смог реализовать явно работающую версию.Так что для тех, кто ищет рабочее решение, вот мое:

private static class RangeVal implements Comparable<RangeVal> {
    public final BigInteger value;
    public int count;

    public RangeVal(BigInteger value, int count) {
        super();
        this.value = value;
        this.count = count;
    }

    @Override
    public String toString() {
        return value + (isStart() ? "S" : "E") + count;
    }

    @Override
    public int compareTo(RangeVal o) {
        // Sort by value first
        int v = value.compareTo(o.value);
        if (v != 0)
            return v;
        // Then sort Starts before ends
        return -count;
    }

    public boolean isStart() {
        return count > 0;
    }

}

/**
 * Sort a List of ranges by their number, then start/end and merge multiple
 * start/ends
 * 
 * @param temp
 *            a list of RangeVal which can be unsorted
 */
private static void preSort(List<RangeVal> temp) {
    Collections.sort(temp);
    RangeVal last = null;
    for (Iterator<RangeVal> iterator = temp.iterator(); iterator.hasNext();) {
        RangeVal rangeVal = iterator.next();
        if ((last != null) && last.value.equals(rangeVal.value) && (last.isStart() == rangeVal.isStart())) {
            iterator.remove();
            last.count += rangeVal.count;
        } else
            last = rangeVal;
    }
}

/**
 * Splits a list into ValueRange Objects that do not overlap each other, but
 * fully represent the ranges given by value
 * 
 * @param value
 *            a list of RangeVal Objects that need to be split
 * @return
 */
private static SortedSet<ValueRange> split(List<RangeVal> value) {
    preSort(value);
    SortedSet<ValueRange> res = new TreeSet<ValueRange>();
    int count = 0;
    BigInteger start = null;
    for (RangeVal rangeVal : value) {
        count += rangeVal.count;
        if (rangeVal.isStart()) {
            if (start != null) {
                //If there was an unended start, then we have to end it just one before the new start
                res.add(new ValueRange(start, rangeVal.value.subtract(BigInteger.ONE)));
            }
            //Set the start to the current Element
            start = rangeVal.value;
        } else {
            //End the current range at this Element
            res.add(new ValueRange(start, rangeVal.value));
            if (count > 0) {
                //If we expect another end later, the element following this will have to start one after
                start = rangeVal.value.add(BigInteger.ONE);
            } else
                //No new range anymore
                start = null;
        }
    }
    return res;
}

public static void main(String[] args) {
    // 5->8 9->10 11
    System.out.println(split(createRanges(5, 8, 9, 10, 11, 11)));
    // 5, 6->7, 8, 9, 10
    System.out.println(split(createRanges(5, 10, 6, 8, 8, 9)));
    System.out.println(split(createRanges(5, 10, 6, 8, 8, 9, 6, 9)));
    System.out.println(split(createRanges(5, 10, 6, 8, 8, 9, 6, 9, 6, 11, 8, 9)));
    System.out.println(split(createRanges(5, 10, 6, 8, 8, 9, 6, 9, 6, 11, 8, 9, 14, 18)));
}

private static List<RangeVal> createRanges(int... r) {
    List<RangeVal> temp = new LinkedList<RangeVal>();
    for (int i = 0; i < r.length; i++) {
        temp.add(new RangeVal(BigInteger.valueOf(r[i]), (i % 2) == 0 ? 1 : -1));
    }
    System.out.println("HDLSimulator.createRanges()" + temp);
    return temp;
}
...