Busco una forma eficaz para eliminar una lista de rangos entre una gama más grande. La lista de rangos estará contenida con la gama más grande
p.ej:
Bigger range: (0,10)
List of Ranges: [(2,7),(4,6),(6,8)]
expected result: {0,1,9,10}
Tengo una implementación más adelante, pero es O (n2) y tiene espacio adicional de tamaño O (n);
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/***
* input -> (0,10) and {(2,7),(4,6),{6,8}}
* output -> {0,1,9,10}
***/
public class RemoveRanges {
public static class Range {
int start;
int end;
public Range(int x, int y){
this.start = x;
this.end = y;
}
}
public static void main(String[] args) {
Range outer = new Range(0,10);
Range r1 = new Range(2,7);
Range r2 = new Range(4,6);
Range r3 = new Range(6,8);
List<Range> rangesToBeRemoved = new ArrayList<>();
rangesToBeRemoved.add(r1);
rangesToBeRemoved.add(r2);
rangesToBeRemoved.add(r3);
System.out.println(removeRanges(outer, rangesToBeRemoved));
}
public static Set<Integer> removeRanges(Range outer, List<Range> rangesToBeRemoved ) {
Set<Integer> outerElements = new HashSet<>();
for (int i = outer.start; i<=outer.end;i++ ){
outerElements.add(i);
}
for (Range range : rangesToBeRemoved) {
for (int j = range.start; j<=range.end; j++) {
outerElements.remove(j);
}
}
return outerElements;
}
}
Consulte la idea @Bohemian cambiando su método de "poner todos los elementos a continuación, eliminar por rango" a "elemento de complemento fuera de rango remove"
- Ordenar la rangesToBeRemoved (por range.start)
- Lazo sobre el elemento de rango y añadir que no se cubre por cadenas
Añadir todos los elementos después del final de la última gama
// assume rangesToBeRemoved has been sorted public static Set<Integer> addElementbyRemovedRanges(Range outer, List<Range> rangesToBeRemoved ) { Set<Integer> outerElements = new HashSet<Integer>(); // this variable record the last element that has handled and act like a borderline int borderElementIndex = outer.start-1; for (Range range : rangesToBeRemoved) { if (range.end <= borderElementIndex ) { // omit this range as it has been cover by previous range(s) continue; } // add range if there is gap between range if (range.start > borderElementIndex ) { addElements(outerElements, borderElementIndex + 1, range.start - 1); } // update borderline borderElementIndex = range.end; } // Add all element after the last range's end addElements(outerElements, borderElementIndex + 1, outer.end); return outerElements; } public static void addElements(Set<Integer> outerElements, int start, int end) { if (start > end) { return; } for (int i=start; i<=end; i++){ outerElements.add(i); } }
Después de la clasificación del rangesToBeRemoved, relación entre dos intervalos se
- Completamente en el rango (por ejemplo, (2,7) y (4,6))
- Parcialmente en el rango (por ejemplo, (2,7) y (6,8))
- Fuera del rango (por ejemplo, (2,3) y (6,8) || (2,3) y (4,8))
Para el caso 1, ignorar el segundo rango. Para el caso 2, actualice la frontera a finales de segundo rango. Para el caso 3, añadir la brecha a la lista de elementos y actualizar la frontera a finales de segundo rango.
El código anterior está tratando de comparar rango virtual (outer.start-1, borderElementIndex) y todos los intervalos en rangesToBeRemoved (ordenadas)
Reutilizar su ejemplo: {(2,7), (4,6), (6,8)}.
- En primer lugar, comparar (-1, -1) con (2,7) y el caso hit 3, añadir la brecha [0,1] en consecuencia establecer y cambiar la borderElementIndex a 7.
- A continuación, comparar (-1,7) con (4,6) y la caja 1 hit, ignorarlo.
- A continuación, comparar (-1,7) con (6,8) y la caja golpe 2, cambie el borderElementIndex a 8.
- Finalmente, append restante brecha [9,10] en conjunto de resultados.
Para reducir aún más el uso del espacio, se puede usar el mismo estado idea en solución @Danny_ds para almacenar el rango de elemento en lugar de elementos individuales.