Java 将范围列表缩小为整数数组

Java 将范围列表缩小为整数数组,java,algorithm,range,Java,Algorithm,Range,我有这样的代码 public List<int[]> getMinifiedRanges(List<int[]> ranges) { for (int[] range : ranges) { } } public List getMinifiedRanges(列表范围){ for(int[]范围:范围){ } } 我的目标是压缩范围列表,由包含范围上限和下限的整数数组表示 ex.[100200][250350]-此示例将返回相同的输入,因为没有重叠

我有这样的代码

public List<int[]> getMinifiedRanges(List<int[]> ranges) {
    for (int[] range : ranges) {

    }
}
public List getMinifiedRanges(列表范围){
for(int[]范围:范围){
}
}
我的目标是压缩范围列表,由包含范围上限和下限的整数数组表示

ex.[100200][250350]-此示例将返回相同的输入,因为没有重叠

[100200][150350][400500]-这将返回[100350][400500],因为第二个范围的下限包含在第一个范围中,因此返回的范围的上限将扩展到350-请注意,当输入为3个数组时,它如何仅返回两个数组


我无法确定如何从当前范围中检索以前的范围,以便扩展下限或上限。

首先,您可以按照以下形式拆分每个范围:

[a,b]范围->(a,1)和(b,2)对


将这些对存储在列表中,然后对列表进行排序。排序后,您可以迭代列表,当(x,1)这样的一对出现时,递增一个变量,当(x,2)这样的一对出现时,递减该变量。变量从0到1的位置是起始索引,变量从1到0的位置是结束索引。

首先,查找数组停止相交的位置。使用此实现,您需要在新的“合并”列表中创建最后一个范围

List ranges=new ArrayList()//保存范围的原始列表
int[]电流;
int[]以前;
列表合并=新建ArrayList()//将以合并的范围结束
int max=ranges.size()-1;
int start=0;
for(int i=1;i先前[1]){
merged.add(newint[]{ranges.get(start)[0],previous[1]});
开始=i;
}
}
merged.add(新的int[]{ranges.get(start)[0],ranges.get(max)[1]});

一旦对范围进行排序(先按最小值排序,然后按最大值排序),每组重叠范围将分组在一起,因此您可以查看列表,对照上一次合并的范围检查每个范围

public static List<int[]> getMinifiedRanges(List<int[]> ranges) {
    List<int[]> minRanges = new ArrayList<>();
    if (ranges.isEmpty()) return minRanges;

    List<int[]> sorted = new ArrayList<>(ranges); // don't modify input list
    Collections.sort(sorted, Comparator.<int[]>comparingInt(r -> r[0]).thenComparingInt(r -> r[1]));

    int[] last = sorted.get(0);
    for (int[] next : sorted.subList(1, sorted.size())) {
        if (last[1] < next[0]) {
            minRanges.add(last);
            last = next;
        } else if (next[1] > last[1]) {
            last = new int[] { last[0], next[1] };
        }
    }
    minRanges.add(last);

    return minRanges;
}
公共静态列表getMinifiedRanges(列表范围){
List minRanges=new ArrayList();
if(ranges.isEmpty())返回minRanges;
列表排序=新建ArrayList(范围);//不修改输入列表
Collections.sort(已排序,Comparator.comparingit(r->r[0])。然后比较int(r->r[1]);
int[]last=sorted.get(0);
for(int[]下一步:sorted.subList(1,sorted.size()){
如果(上一个[1]<下一个[0]){
添加(最后一个);
最后一个=下一个;
}else if(下一个[1]>最后一个[1]){
last=newint[]{last[0],next[1]};
}
}
添加(最后一个);
返回范围;
}

一旦你混合了一个系列,你怎么能找回原来的呢?在您的[100200]与[250350]-->[100350]的混合中,我不知道如何从输出中恢复原始范围。我误解了你的问题吗?按下限排序,迭代,如果当前范围与下一个范围重叠(递归),然后使用当前下限和最大上限创建一个范围。@mba12一旦范围混合,我将不再需要获得原始范围,混合范围是最终输出的一部分,需要混合的任何其他范围都遵循相同的过程。对于您实际遇到的问题,要么保留一个存储最后一个结果的
int[]
变量,要么使用一个“normal”(非For each)For循环(访问最后一个元素很简单)。但是,通过将开始和结束分离到同一个
int
s列表中并对其进行迭代,这个问题更容易解决。可能的重复操作在
[0,9],[1,2]
上失败。谢谢!此实现是否假定对范围进行排序?一些假设-对范围数组进行排序,以使每个数组的第一个元素大于或等于上一个元素。此外,在Sean Van Gorder的示例中,由于假设序列中的后续范围不会是早期范围的子集,因此将失败。谢谢Sean,实现似乎运行正常-我感谢您的知识。您能验证我的时间复杂性分析是否正确吗?排序需要O(n)个log(n)时间,for循环需要O(n)个时间,所以最终的复杂度是O(n(n log(n))?谢谢你,排序和for循环每次只做一次,所以它将是O(n log n)+O(n),我相信这将简化为O(n log n)。
public static List<int[]> getMinifiedRanges(List<int[]> ranges) {
    List<int[]> minRanges = new ArrayList<>();
    if (ranges.isEmpty()) return minRanges;

    List<int[]> sorted = new ArrayList<>(ranges); // don't modify input list
    Collections.sort(sorted, Comparator.<int[]>comparingInt(r -> r[0]).thenComparingInt(r -> r[1]));

    int[] last = sorted.get(0);
    for (int[] next : sorted.subList(1, sorted.size())) {
        if (last[1] < next[0]) {
            minRanges.add(last);
            last = next;
        } else if (next[1] > last[1]) {
            last = new int[] { last[0], next[1] };
        }
    }
    minRanges.add(last);

    return minRanges;
}