Wie finde ich die maximale Menge von Elementen


14

Ich habe ein algorithmisches Problem.

TnSTeinSein|S|

Beispielsweise:

  1. Wenn = [1, 3, 4, 1, 3, 6] ist, kann [3, 3, 6] oder [3, 4, 6] oder [4, 3, 6] sein.TS
  2. In = [7, 5, 1, 1, 7, 4] ist [7, 5, 7, 4].TS

Ich habe diese rekursive Funktion ausprobiert.

function(T):
    if minimum(T) >= length(T): 
        return T
    else: 
        return function(T\minimum(T))

Gibt es einen nicht-rekursiven Algorithmus? (Ich habe meinen rekursiven Algorithmus nicht überprüft, damit er einen Fehler aufweist.)

Antworten:


14

Sortieren Sie T. Dann nehmen Sie Elemente während T[i] >= i+1.

Zum Beispiel sorted(T)=[6,4,3,3,1,1]. Dann T[0] = 6 > 1, T[1] = 4 > 2, T[2] = 3 <= 3und schließlich, T[3] = 3 < 4so haben wir S = [T[0], T[1], T[2]].


3
Hier fehlt natürlich die andere Lösung , aber anscheinend suchte das OP nach einer beliebigen Lösung und nicht nach allen Lösungen. {6,3,3}
Rick Decker

2
Es stimmt die Anzahl der Elemente. Wir wissen, dass wir Lösungen mit 3 Elementen haben, aber nicht mit 4; In diesem Fall haben wir 4 Elemente ≥ 3, sodass wir wissen, dass wir 3 davon für eine Lösung auswählen können.
gnasher729

3
Ich würde mich über ein Argument der Richtigkeit freuen.
Raphael

Ich denke, Sie könnten es wahrscheinlich in O (n) Zeit mit einer Variante von Introselect tun.
user2357112 unterstützt Monica

8

Von meinem Kommentar ursprünglich: Dies ist eng mit einer Menge allgegenwärtig in der akademischen Produktivität Beurteilung im Zusammenhang, der Hirsh Index besser bekannt als die -Indexh . Kurz gesagt ist es , wenn die Anzahl von Publikationen definiert man hat , so dass jede von ihnen hat zumindest h Zitierungen (die größte derartige h ).hhh

Der einzige Unterschied zwischen Ihnen und Ihrem Problem besteht darin, dass Sie sich nicht nur dafür interessieren, wie viele Veröffentlichungen das Kriterium erfüllen, sondern auch, wie oft sie zitiert werden. Dies ist jedoch eine geringfügige Änderung. Die Daten sind schon da, der ursprüngliche Algorithmus lässt sie einfach fallen.

Die allgemein umgesetzte Berechnung ist eher unkompliziert und stimmt mit der Antwort von Karolis Juodelė überein .

Update: Abhängig von der Größe und dem Charakter Ihrer Daten kann es sich lohnen, Methoden zu untersuchen, die das Array teilweise sortieren, indem Daten über und unter einem Dreh- und Angelpunkt gefiltert werden (QuickSort fällt ein). Dann, je nachdem, ob zu wenig oder zu viele vorhanden sind, passen Sie den Drehpunkt an und wiederholen Sie den Vorgang für die Teilmenge, die ihn enthält, und so weiter. Sie brauchen keine Reihenfolge zwischen Elementen, die höher als , und schon gar nicht zwischen denen, die niedriger als h sind. Wenn Sie zum Beispiel alle Elemente gefunden haben, die größer oder gleich h 1 sind und von denen es weniger als h 1 gibt , müssen Sie diese Untergruppe nicht erneut berühren, sondern nur hinzufügen. Dadurch wird die inhärente Rekursion in eine Endrekursion umgewandelt und kann somit als Schleife umgeschrieben werden.hh1h1

Mein Haskell ist ein bisschen rostig, aber dies sollte das tun, was ich oben beschrieben habe und scheint zu funktionieren. Hoffe, es kann bis zu einem gewissen Grad verstanden werden, ich freue mich, weitere Erklärungen zu geben.

-- just a utility function
merge :: [a] -> [a] -> [a]
merge [] ys = ys
merge (x:xs) ys = x : merge xs ys

-- the actual implementation
topImpl :: [Int] -> [Int] -> [Int]
topImpl [] granted = granted
topImpl (x:xs) granted
  | x == (1 + lGreater + lGranted) = x : merge greater granted
  | x > (1 + lGreater + lGranted) = topImpl smaller (x : merge greater granted)
  | otherwise = topImpl greater granted
  where smaller = [y | y <- xs, y < x]
        greater = [y | y <- xs, y >= x]
        lGreater = length greater
        lGranted = length granted

-- starting point is: top of whole array, granted is empty
top :: [Int] -> [Int]
top arr = topImpl arr []

Die Idee ist, in dem, grantedwas Sie wissen, zu sammeln , dass es definitiv zum Ergebnis beiträgt, und es nicht weiter zu sortieren. Wenn greaterzusammen mit xpasst, haben wir Glück, sonst müssen wir mit einer kleineren Teilmenge versuchen. (Der Zapfen xist einfach , was passiert ist das erste Element der Unterliste sein , die derzeit in Betracht gezogen wird .) Beachten Sie, dass der wesentliche Vorteil gegenüber Einnahme größten Elemente eines nach dem anderen ist , dass wir dies tun auf Blöcke von durchschnittlicher Größe und müssen nicht weiter sortiert werden.remeinichnichnG/2

Beispiel:

Lass uns dein Set nehmen [1,3,4,1,3,6].

  1. x = 1, granted = [], greater = [3,4,1,3,6]. Autsch, wir treffen einen pathologischen Fall, wenn der Drehzapfen smallerdirekt im ersten Schritt zu klein ist (tatsächlich so klein, dass er leer ist). Zum Glück ist unser Algo dazu bereit. Es verwirft xund versucht es erneut mit greaterallein.

  2. x = 3, granted = [], greater = [4,3,6]. Zusammen bilden sie ein Array der Länge 4, aber wir haben nur das von unten auf 3 begrenzt, das ist also zu viel. Wiederholen Sie auf greaterallein.

  3. x = 4, granted = [], greater = [6]. Dies ergibt ein Array von 2 Elementen ≥ 4, anscheinend haben wir für einige mehr davon Verwendung. Behalte dies bei und wiederhole es smaller = [3].

  4. x = 3, granted = [4,6], greater = []. Dies ergibt zusammen ein Array von 3 Elementen ≥ 3, sodass wir unsere Lösung haben [3,4,6]und zurückkehren können. (Beachten Sie, dass die Permutation abhängig von der Reihenfolge der Eingabe variieren kann, aber immer die höchstmöglichen Terme enthält, niemals [3,3,6]oder [3,3,4]für Ihr Beispiel.)

(Übrigens ist zu beachten, dass die Rekursion tatsächlich nur zu einem Zyklus zusammengebrochen ist.) Die Komplexität ist aufgrund der vielen gespeicherten Vergleiche etwas besser als Quicksort:

n-1

Ö(Logn)Ö(n)

nÖ(n2)

Es gibt ein paar unnötige Vergleiche im obigen Code, wie die Berechnung, smallerob wir es brauchen oder nicht, sie können leicht entfernt werden. (Ich denke, dass eine faule Bewertung dies jedoch erledigen wird.)


6

An Ihrem Algorithmus ist nichts auszusetzen, und natürlich können die meisten rekursiven Algorithmen in Schleifen konvertiert werden, hier eine Schleifenversion Ihres rekursiven Codes:

function(T):
    while minimum(T) <= lenght(T):
         remove minimum(T) from T
    loop

6
Alle rekursiven Algorithmen können in Schleifen umgewandelt werden. Schließlich weiß eine Turing-Maschine nichts über Rekursion.
David Richerby

4

Jeder rekursive Algorithmus kann zur Verwendung der Iteration umgeschrieben werden. Schließlich weiß eine Turing-Maschine nichts über Rekursion, kann aber jeden Algorithmus implementieren. Im Prinzip können Sie Ihre rekursive Funktion umschreiben, indem Sie Ihren eigenen Stapelmanipulationscode schreiben, um sich die Werte der Funktionsparameter und etwaiger lokaler Variablen zu merken. In diesem speziellen Fall ist Ihre Funktion rekursiv (sobald ein rekursiver Aufruf zurückkehrt, kehrt auch das Objekt, das sie aufgerufen hat, sofort zurück), sodass Sie den Stack nicht einmal warten müssen.


3

Verwenden Sie einen Min-Heap, um eine Teil-Heap-Sortierung durchzuführen, da nicht das gesamte Array sortiert werden muss.

Knallen Sie die Elemente so lange, bis Sie den angegebenen Schwellenwert überschreiten.


2
Auch hier würde ich mich über eine Idee der Korrektheit freuen.
Raphael
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.