Ich habe eine Liste annehmen
listA=[679,890,907,780,5230,781]
und wollen einige Elemente löschen, die in einem anderen existierte wird
listB=[907,5230]
in kürzester Zeit Komplexität?
Ich kann dieses Problem tut Mittel, durch die Verwendung von zwei „for-Schleifen“ O (n2) Zeit Komplexität, aber ich mag diese Komplexität O (nlog (n)) oder O (n) reduzieren? Ist es möglich?
Es ist möglich - wenn einer der Listen sortiert. Unter der Annahme , dass die Liste sortiert wird A und B Liste ist unsortiert, mit jeweiligen Abmessungen M
und N
die minimale Zeitkomplexität alle Liste B der Elemente aus der Liste A zu entfernen sein wird O((N+M)*log(M))
. Die Art und Weisen Sie dies erreichen können , ist durch binäre Suche - jeder Nachschlag für ein Element in der Liste A dauert O(log(M))
Zeit, und es gibt N
Lookups (ein für jedes Element in der Liste B). Da es braucht O(M*log(M))
Zeit A zu sortieren, ist es effizienter für riesige Listen alle Elemente zu sortieren und dann entfernen, mit einer Zeitkomplexität O((N+M)*log(M))
.
Auf der anderen Seite, wenn Sie nicht über eine sortierte Liste haben, verwenden Sie einfach Collection.removeAll , die eine Zeitkomplexität hat O(M*N)
in diesem Fall. Der Grund für diese Zeit Komplexität ist , dass removeAll
tut (standardmäßig) so etwas wie der folgenden Pseudo - Code:
public boolean removeAll(Collection<?> other)
for each elem in this list
if other contains elem
remove elem from this list
Da contains
eine Zeitkomplexität hat O(N)
für Listen, und Sie am Ende tun M
Iterationen, nimmt diese O(M*N)
Zeit insgesamt.
Schließlich, wenn Sie die Zeitkomplexität minimieren wollen removeAll
(mit möglicherweise verschlechtern reale Welt Performance) können Sie folgendes tun:
List<Integer> a = ...
List<Integer> b = ...
HashSet<Integer> lookup = new HashSet<>(b);
a.removeAll(lookup);
Für schlechte Werte von b, die Zeit zu konstruieren lookup
könnte zu Zeit in Anspruch nehmen O(N*log(N))
, wie gezeigt hier ( „pathologisch verteilt Keys“). Danach wird rufenden removeAll
nehmen O(1)
für contains
über M
Iterationen, wobei O(M)
Zeit auszuführen. Daher ist die Zeitkomplexität dieses Ansatzes O(M + N*log(N))
.
So gibt es Ansätze , drei hier. One bietet Ihnen mit der Zeit Komplexität O((N+M)*log(M))
, ein anderer bietet Ihnen mit der Zeit Komplexität O(M*N)
und die letzte liefert Ihnen Zeitkomplexität O(M + N*log(N))
. Bedenkt man, dass die ersten und letzten Ansätze in Zeitkomplexität ähnlich sind (wie log
sehr klein zu sein scheint auch für eine große Zahl), würde ich vorschlagen , mit der naiven gehen O(M*N)
für kleine Eingänge und einfachsten O(M + N*log(N))
für mittlere Eingänge. An der Stelle , wo die Speicherauslastung von der Erstellung einer HashSet zu leiden beginnt zu speichern , die Elemente von B (sehr große Eingänge), würde ich wechseln schließlich auf die komplexeren O((N+M)*log(M))
Ansatz.
Sie können eine AbstractCollection.removeAll Implementierung finden hier .
Edit:
Der erste Ansatz für Arraylisten nicht so gut funktionieren - von der Mitte der Liste A zu entfernen braucht O(M)
Zeit, offenbar. Stattdessen Sortierliste B ( O(N*log(N))
), und eine Iteration durch die Liste A, Elemente gegebenenfalls zu entfernen. Dies dauert O((M+N)*log(N))
Zeit und ist besser als das , O(M*N*log(M))
dass Sie sich mit enden , wenn eine Arraylist verwenden. Leider erfordert die Teil dieses Algorithmus „Elemente gegebenenfalls zu entfernen“ , dass Sie Daten zu erstellen , um die nicht entfernten Elemente zu speichern O(M)
, wie Sie in diesem Fall keinen Zugriff auf den internen Datenfeld der Liste A. haben, ist es streng besser mit dem HashSet Ansatz zu gehen. Dies liegt daran , (1) die Zeitkomplexität O((M+N)*log(N))
tatsächlich schlechter als die Zeitkomplexität für die HashSet Methode ist, und (2) der neue Algorithmus speichert nicht auf Speicher. Deshalb,Verwenden Sie nur den ersten Ansatz , wenn Sie eine Liste mit haben O(1)
Zeit für die Entfernung (zB LinkedList) und eine große Menge an Daten . Andernfalls verwenden removeAll . Es ist einfacher, oft schneller, und von Bibliothek - Designer unterstützt (zB Arraylist hat eine individuelle removeAll
Implementierung , die es mit vernachlässigbaren zusätzlichen Speichern anstelle der quadratischen Zeit in Anspruch nimmt linear erlaubt).