4 Stimmen

Bereichsteilungsproblem

Leute,

Ich habe von diesem Problem vor einiger Zeit gehört. Ich dachte daran, es zu veröffentlichen, um einige Ansichten darüber zu bekommen, wie man dies machen könnte, z.B. durch Verwendung eines Konstrukts oder anderer effizienter Mittel (spezialisierte Bäume könnten verwendet werden)

Gegeben eine Reihe von Bereichspaaren (5,18) (12,23) (15,30)

teile sie in alle möglichen Teilbereiche auf, die sich mit anderen Bereichen im Set überschneiden, wie (5,11) (12,14) (15,18) (19,23) (24,30)

Danke euch allen, das schätze ich...

Rajan...

PS Ist das ein Standardproblem, wenn ja, würde gerne den Namen wissen

5voto

moinudin Punkte 125641

Werfen Sie alle Bereichsendpunkte in eine Liste, markieren Sie sie jedoch als Start-/Endpunkte.

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

Sortieren Sie sie nach Position und brechen Sie Unentschieden, indem Sie Startpunkte vor Endpunkten setzen.

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

Dann können Sie die Bereiche herausfinden, indem Sie diese Liste durchgehen und dabei verfolgen, wie viele Start- minus Endpunkte wir bisher verarbeitet haben. Wenn wir einen Startpunkt sehen, ist das der Beginn eines neuen Bereichs, den wir ausgeben sollen. Wenn unsere Zählung positiv ist, müssen wir jedoch zuerst den aktuellen Bereich beenden. Wenn wir einen Endpunkt sehen, beenden wir den aktuellen Bereich.

1voto

Karsten Punkte 11

Ok, nach einigem Tüfteln konnte ich anscheinend eine funktionierende Version implementieren. Also für diejenigen, die nach einer funktionierenden Lösung suchen, hier ist meine:

private static class RangeVal implements Comparable {
    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) {
        // Zuerst nach Wert sortieren
        int v = value.compareTo(o.value);
        if (v != 0)
            return v;
        // Dann Starts vor Ende sortieren
        return -count;
    }

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

}

/**
 * Eine Liste von Bereichen nach ihrer Nummer sortieren, dann Anfang/Ende sortieren und mehrere Start-/Endwerte zusammenführen
 * 
 * @param temp
 *            eine Liste von RangeVal, die unsortiert sein kann
 */
private static void preSort(List temp) {
    Collections.sort(temp);
    RangeVal last = null;
    for (Iterator 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;
    }
}

/**
 * Teilt eine Liste in ValueRange-Objekte auf, die sich nicht überschneiden, aber die von den Werten angegebenen Bereiche vollständig darstellen
 * 
 * @param value
 *            eine Liste von RangeVal-Objekten, die aufgeteilt werden müssen
 * @return
 */
private static SortedSet split(List value) {
    preSort(value);
    SortedSet res = new TreeSet();
    int count = 0;
    BigInteger start = null;
    for (RangeVal rangeVal : value) {
        count += rangeVal.count;
        if (rangeVal.isStart()) {
            if (start != null) {
                //Wenn ein Start nicht beendet wurde, müssen wir ihn gerade vor dem neuen Start beenden
                res.add(new ValueRange(start, rangeVal.value.subtract(BigInteger.ONE)));
            }
            //Setze den Start auf das aktuelle Element
            start = rangeVal.value;
        } else {
            //Beende den aktuellen Bereich bei diesem Element
            res.add(new ValueRange(start, rangeVal.value));
            if (count > 0) {
                //Wenn wir später ein weiteres Ende erwarten, muss das Element nach diesem um eins weiter starten
                start = rangeVal.value.add(BigInteger.ONE);
            } else
                //Kein neuer Bereich mehr
                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 createRanges(int... r) {
    List temp = new LinkedList();
    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;
}

1voto

Jitendra Kulkarni Punkte 813

Vielleicht fehlt mir etwas, aber das scheint wie eine einfache Lösung auszusehen: Werfen Sie alle Zahlen in einen C++ STL Set-Container. Sie werden automatisch in aufsteigender Reihenfolge sortiert. so werden sie in dieser Reihenfolge ausgelesen: 5,12,15,18,23,30 Also, wenn Sie Überlappungen tolerieren können, dann sind: (5,12) (12,15) (15,18), (18,23) (23,30) die Bereich, die konstruiert werden, indem jede Zahl außer der ersten und der letzten zweimal wiederholt wird und dann zwei Zahlen gruppiert werden.

Wenn Sie keine Überlappungen tolerieren können, können die Bereich konstruiert werden, indem eine inkrementierte Zahl in die Liste eingefügt wird anstatt sie zu wiederholen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X