需求:给定多个连续的区间,将区间进行合并,输出一个或多个没有交集的连续区间。
支持泛型,可以用数值或者字符串表示区间(实际上是Comparable接口)。
环境:jdk1.8
package cn.xxx.utils.interval;
import net.sf.json.JSONObject;
/**
* 区间
* */
public class Interval<T extends Comparable<T>>{
private T begin;
private T end;
public static <E extends Comparable<E>> Interval<E> of(E begin,E end){
Interval<E> ts = new Interval<>();
if(begin.compareTo(end)>0){
throw new RuntimeException("begin should not bigger than end");
}
ts.begin = begin;
ts.end = end;
return ts;
}
public T getBegin() {
return begin;
}
public T getEnd() {
return end;
}
@Override
public String toString() {
return JSONObject.fromObject(this).toString();
}
}
package cn.xxx.utils.interval;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import org.springframework.util.Assert;
/*区间合并器*/
public class Merger {
public <E extends Comparable<E>> List<Interval<E>> merge(List<Interval<E>> intervals) {
Assert.isTrue(!intervals.isEmpty(), "interval list size is 0");
intervals.sort((o1, o2) -> o2.getBegin().compareTo(o1.getBegin()));
Stack<Interval<E>> stack = new Stack<>();
List<Interval<E>> result = new ArrayList<>();
intervals.forEach(item -> stack.push(item));
while (stack.size() > 1) {
Interval<E> i1 = stack.pop();
Interval<E> i2 = stack.pop();
List<Interval<E>> mergedList = mergeSingle(i1, i2);
if (mergedList.size() == 2) {
result.add(mergedList.get(0));
}
stack.push(mergedList.get(mergedList.size()-1));
}
result.add(stack.pop());
return result;
}
private <E extends Comparable<E>> List<Interval<E>> mergeSingle(Interval<E> first, Interval<E> second) {
Assert.isTrue(first.getBegin().compareTo(second.getBegin())<=0,"first interval's begin should less than second's");
List<Interval<E>> result = new ArrayList<>(2);
if(first.getEnd().compareTo(second.getBegin())<0){
result.add(first);
result.add(second);
}else{
E end;
if(first.getEnd().compareTo(second.getEnd())>=0){
end = first.getEnd();
}else{
end = second.getEnd();
}
result.add(Interval.of(first.getBegin(), end));
}
return result;
}
}
单元测试
package cn.xxx.utils.interval;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import junit.framework.Assert;
public class MergerTest {
@Test
public void test(){
List<Interval<Long>> intervals = new ArrayList<>();
intervals.add(Interval.of(1L, 5L));
intervals.add(Interval.of(2L, 3L));
intervals.add(Interval.of(8L, 10L));
intervals.add(Interval.of(4L, 6L));
intervals.add(Interval.of(7L, 8L));
Merger merger = new Merger();
List<Interval<Long>> newIntervals = merger.merge(intervals);
System.out.println(newIntervals);
Assert.assertTrue(newIntervals.size()==2);
}
}