在准备一些编程访谈时,我遇到了一个很好的问题。
给定一组可能重叠的区间,您需要编写一个函数来返回它们之间的所有基本区间。例如:如果给定间隔作为以下对列表:{{1,5},{3,10},{5,11},{15,18},{16,20}},那么您需要返回以下内容:
{{1,3},{3,5},{5,10},{10,11},{15,16},{16,18},{18,20}}
请注意以上答案中的以下内容:
Java中的方法签名:
List<Pair<Integer, Integer>> generateElementaryIntervals(List<Pair<Integer, Integer> intervals)
我想象的一个解决方案是将输入分成非交叉集,然后对每个非交叉集中的所有数字进行简单的O(NlogN)排序将得出答案。有更有效的方法吗?
答案 0 :(得分:8)
您可以先将此问题分解为嵌套间隔,然后分别处理每个嵌套。通过嵌套,我的意思是至少共享一个点的间隔。对于您给出的示例:
{{1,5}, {3,10}, {5,11}, {15,18}, {16,20}}
有两种嵌套:
{1,5}, {3,10}, {5,11}
和
{15,18}, {16,20}
通常,要确定嵌套,您可以根据左端点对间隔进行排序(如示例所示),然后在看到{x,y}, {x',y'}
y < x'
时运行并开始新的嵌套
对于嵌套,“基本区间”由值的排序序列(不重复)形成。在示例中,嵌套提供
(1,3,5,10,11) -> {1,3}, {3,5}, {5,10}, {10,11}
和
(15,16,18,20) -> {15,16}, {16,18}, {18,20}
因此整体算法可能如下所示:
{x,y}, {x',y'}
y < x'
{x,y}
,制作已排序的端点列表(无重复),比如a0,a1,...,ak
{ai,a(i+1)}
i = 0...k-1
{x,y}
的时间间隔,然后从第2步继续答案 1 :(得分:1)
您可以对端点进行排序,然后按顺序迭代。为了知道您是否在场,您可以保留覆盖每个点的间隔数。 间隔的左端贡献+1,而右边贡献-1: (请注意,我使用TreeMap,已排序)
static class Pair<T, K> {
public Pair(T first, K second){
this.first = first;
this.second = second;
}
public String toString(){
return "(" + first + ", " + second + ")";
}
T first;
K second;
}
static List<Pair<Integer, Integer>> generateElementaryIntervals(List<Pair<Integer, Integer>> intervals) {
TreeMap<Integer, Integer> overlaps = new TreeMap<Integer, Integer>();
for(Pair<Integer, Integer> interval : intervals){
int value = overlaps.containsKey(interval.first) ? overlaps.get(interval.first)+1 : 1;
overlaps.put(interval.first, value);
value = overlaps.containsKey(interval.second) ? overlaps.get(interval.second)-1 : -1;
overlaps.put(interval.second, value);
}
List<Pair<Integer, Integer>> retValue = new ArrayList<Pair<Integer,Integer>>();
int overlap = 0;
boolean in = false;
int last = 0;
for(int point : overlaps.keySet()){
if(in)
retValue.add(new Pair(last, point));
overlap += overlaps.get(point);
last = point;
in = overlap > 0;
}
return retValue;
}
public static void main(String[] args) {
List<Pair<Integer, Integer>> l = new ArrayList<Pair<Integer, Integer>>();
l.add(new Pair<Integer, Integer>(1,5));
l.add(new Pair<Integer, Integer>(3,10));
l.add(new Pair<Integer, Integer>(5,11));
l.add(new Pair<Integer, Integer>(15,18));
l.add(new Pair<Integer, Integer>(16,20));
for(Object o : generateElementaryIntervals(l)){
System.out.println(o.toString());
}
}
答案 2 :(得分:0)
一个简单的算法就是简单地读取整个数字列表,并为每对中的每个项目创建一个元素。
每个元素都会存储两个值:number
,以及它是第一个还是第二个数字(来自输入)。
然后对这些对进行排序,首先是内部number
,然后按其位置(second
将在first
之前进行排序)
要打印出间隔列表,您可以使用以下规则打印每个数字和下一个数字:
second
个数字,然后是first
个数字,则不会打印该基本间隔,因为该范围内没有值。