Je cherche un moyen efficace de supprimer une liste de plages d'une plus grande gamme. La liste des plages sera contenu avec la plus grande gamme
par exemple:
Bigger range: (0,10)
List of Ranges: [(2,7),(4,6),(6,8)]
expected result: {0,1,9,10}
J'ai une mise en œuvre ci-dessous, mais il est O (n2) et prend plus d'espace de taille 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;
}
}
Reportez-vous à idée @Bohemian en changeant votre méthode de « ajouter tout élément puis retirez par gamme » à « élément rapporté de supprimer plage »
- Trier les rangesToBeRemoved (par range.start)
- Boucle sur l'élément de gamme et ajouter qui couvre pas par des plages
Ajouter tout élément après la fin de la dernière plage
// 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); } }
Après le tri de la rangesToBeRemoved, la relation entre les deux gammes sont
- Complètement dans la gamme (par exemple (2,7) et (4,6))
- En partie dans la gamme (par exemple (2,7) et (6,8))
- Pas dans la gamme (par exemple, (2,3) et (6,8) || (2,3) et (4,8))
Pour le cas 1, ignorer la deuxième plage. Pour le cas 2, mettez à jour la frontière à la fin de la deuxième plage. Pour le cas 3, ajouter l'écart à la liste des éléments et mettre à jour la frontière à la fin de la deuxième plage.
Le code ci-dessus tente de comparer plage virtuelle (outer.start-1, borderElementIndex) et toutes les gammes de rangesToBeRemoved (triée)
Réutiliser votre exemple: {(2,7), (4,6), (6,8)}.
- Tout d'abord, comparer (-1, -1) (2,7) et cas de succès 3, ajouter l'écart [0,1] en jeu de résultats et changer le borderElementIndex à 7.
- Ensuite, comparez (-1,7) avec (4,6) et cas de succès 1, l'ignorer.
- Ensuite, comparez (-1,7) avec (6,8) et cas de succès 2, changer le borderElementIndex à 8.
- Greffer écart restant [9,10] dans le jeu de résultats.
Pour réduire davantage l'utilisation de l'espace, vous pouvez utiliser le même état d'idée en solution @Danny_ds pour stocker la gamme d'éléments au lieu d'éléments individuels.