人,
很久以前就听说过这个问题了。考虑发布它,以获得一些观点,如使用一些构造或其他有效的手段(专门的树可能)
给出一组成对的范围(5,18)(12,23)(15,30)
将它们分成所有可能的子范围,这些子范围与集合中的其他范围重叠。 像(5,11)(12,14)(15,18)(19,23)(24,30)
感谢所有人,感谢...
...拉詹
PS是一个标准问题,如果是的话,想知道它的名字
答案 0 :(得分:5)
将所有范围端点清除到列表中,但将它们标记为开始/结束点。
[(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 :(得分:1)
好的,经过一些修修补补后,我能够实现一个看似工作的版本。因此,对于那些正在寻找可行解决方案的人来说,这是我的:
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;
}
答案 2 :(得分:1)
也许我错过了什么,但这似乎是一个简单的解决方案: 将所有数字都放在C ++ STL集容器中。它们将按升序自动排序。所以他们会以这种方式宣读: 5,12,15,18,23,30 所以,如果你能够容忍重叠,那么: (5,12)(12,15)(15,18),(18,23)(23,30)是通过重复每个数字两次期望第一个和最后一个然后将两个数字分组而构建的范围。 / p>
如果你不能容忍重叠,可以通过在列表中加一个递增的数字而不是重复来构造范围。