0Pricing
DSA Interview Prep · Lektion

Python heapq und Tricks für Max-Heaps

Verwenden Sie heapq.heappush/heappop, negieren Sie Werte zur Simulation eines Max-Heaps und wenden Sie heapq.nlargest/nsmallest für schnelle Top-k-Abfragen an.

Python heapq und Tricks für Max-Heaps ist eine kostenlose DSA Interview Prep-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des DSA Interview Prep-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der DSA Interview Prep-Kurs umfasst insgesamt 4 Lektionen.

Überblick über Pythons heapq-Modul

Pythons heapq-Modul stellt einen Min-Heap bereit, der auf einer gewöhnlichen Python-Liste implementiert ist. Anders als eine spezielle Heap-Klasse arbeitet heapq direkt mit vorhandenen Listen. Die Funktionen des Moduls sind: heapify zum Aufbau eines Heaps in O(n), heappush zum Hinzufügen eines Elements in O(log n), heappop zum Entfernen des Minimums in O(log n) sowie heappushpop / heapreplace für kombinierte Effizienz.

import heapq

# heapq operates on plain Python lists
heap = []
heapq.heappush(heap, 5)
heapq.heappush(heap, 2)
heapq.heappush(heap, 8)
heapq.heappush(heap, 1)

print('Heap array:', heap)          # internal array (not sorted!)
print('Peek min:', heap[0])         # O(1) min access
print('Pop min:', heapq.heappop(heap))  # 1
print('Next min:', heap[0])         # 2

# heapify: turn any list into a heap in O(n)
data = [9, 4, 7, 1, 3, 6, 2]
heapq.heapify(data)
print('Heapified:', data, '| min:', data[0])

Max-Heap durch Negieren von Werten

Pythons heapq stellt nur einen Min-Heap bereit. Um einen Max-Heap zu simulieren, negieren Sie alle Werte vor dem Einfügen und negieren sie beim Entfernen erneut. Das funktioniert, weil der Heap anhand der gespeicherten Werte ordnet und das Negieren die Reihenfolge umkehrt. Denken Sie immer daran, auf beiden Seiten zu negieren: vor dem Einfügen negieren, nach dem Entfernen erneut negieren. Einen dieser beiden Schritte zu vergessen, ist ein häufiger Fehler in Interviews.

import heapq

max_heap = []
for val in [5, 1, 8, 3, 9, 2]:
    heapq.heappush(max_heap, -val)  # negate on push

print('Max-heap internal:', max_heap)  # all negated

# Pop in descending order:
results = []
while max_heap:
    results.append(-heapq.heappop(max_heap))  # negate on pop
print('Sorted descending:', results)  # [9, 8, 5, 3, 2, 1]

# Common pattern: top-k largest
data = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
k = 3
heap = []
for x in data:
    heapq.heappush(heap, -x)
print('Top', k, ':', [-heapq.heappop(heap) for _ in range(k)])

heapq.nlargest und nsmallest

heapq.nlargest(k, iterable) und heapq.nsmallest(k, iterable) geben die k größten bzw. kleinsten Elemente zurück. Sie arbeiten in O(n log k) und sind damit effizienter als eine vollständige Sortierung (O(n log n)), wenn k deutlich kleiner als n ist. Intern verwenden sie einen Heap der Größe k. Wenn k nahe bei n liegt, verwendet Python stattdessen eine vollständige Sortierung. Verwenden Sie diese Funktionen für einmalige Top-k-Abfragen, ohne einen persistenten Heap zu verwalten.

import heapq

data = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 7]

# Top 3 largest:
print(heapq.nlargest(3, data))   # [9, 8, 7]
# Top 3 smallest:
print(heapq.nsmallest(3, data))  # [1, 1, 2]

# With a key function:
words = ['banana', 'apple', 'cherry', 'date', 'elderberry']
print(heapq.nlargest(2, words, key=len))   # ['elderberry', 'banana']
print(heapq.nsmallest(2, words, key=len))  # ['date', 'apple']

# Note: when k ~ n, use sorted() instead:
# sorted(data)[-k:]  or  sorted(data, reverse=True)[:k]

Heap mit Tupeln für komplexe Schlüssel

Wenn Heap-Elemente einen benutzerdefinierten Vergleichsschlüssel benötigen, speichern Sie sie als Tupel (priority, data). Pythons heapq vergleicht Tupel Element für Element und vergleicht daher zunächst die Prioritäten. Bei gleichen Prioritäten wird das zweite Element verglichen. Das kann zu Fehlern führen, wenn die Daten nicht vergleichbar sind. Am sichersten ist es, einen eindeutigen Zähler als Tie-Breaker einzubeziehen, damit Datenelemente niemals direkt miteinander verglichen werden.

import heapq
import itertools

# Pattern: (priority, counter, item)
# Counter ensures unique tiebreaker, avoids comparing items
counter = itertools.count()
heap = []

def push_task(priority, task):
    heapq.heappush(heap, (priority, next(counter), task))

push_task(3, 'low priority task')
push_task(1, 'high priority task')
push_task(2, 'medium priority task')
push_task(1, 'another high priority')

while heap:
    pri, cnt, task = heapq.heappop(heap)
    print(f'P{pri}: {task}')
# Output in priority order: P1, P1, P2, P3

heapq.merge: Sortierte Iterables zusammenführen

heapq.merge(*iterables) führt mehrere sortierte Iterables verzögert zu einer einzigen sortierten Ausgabe zusammen, ohne alle Daten in den Speicher zu laden. Dies entspricht einem k-Wege-Merge mit einem Min-Heap der Größe k und wird in externen Sortieralgorithmen verwendet. Die Funktion gibt einen Iterator zurück, sodass die Elemente einzeln erzeugt werden – ideal für große Datenmengen oder Streaming-Szenarien.

import heapq

# Merge multiple sorted lists efficiently
sorted_lists = [
    [1, 5, 9],
    [2, 6, 8],
    [3, 4, 7]
]

# heapq.merge takes sorted iterables and returns a merged sorted iterator
merged = list(heapq.merge(*sorted_lists))
print('Merged:', merged)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]

# The k-way merge manually (educational version):
def merge_k_sorted(lists):
    heap = []
    for i, lst in enumerate(lists):
        if lst:
            heapq.heappush(heap, (lst[0], i, 0))
    result = []
    while heap:
        val, list_idx, elem_idx = heapq.heappop(heap)
        result.append(val)
        if elem_idx + 1 < len(lists[list_idx]):
            heapq.heappush(heap, (lists[list_idx][elem_idx+1], list_idx, elem_idx+1))
    return result

print('Manual k-way:', merge_k_sorted(sorted_lists))

Muster für Lazy Deletion bei Heaps

Wenn Sie beliebige Elemente aus einem Heap entfernen müssen, deren Index Sie aber nicht kennen, verwenden Sie Lazy Deletion: Markieren Sie Elemente in einer separaten Menge als gelöscht und überspringen Sie sie beim Entfernen. Dies hat amortisiert eine Laufzeit von O(log n) und vermeidet die Komplexität der Indexverwaltung. Dieser Ansatz ist Standard im Dijkstra-Algorithmus mit doppelten Einträgen und bei Simulationen von Aufgabenplanern.

import heapq

class LazyHeap:
    def __init__(self):
        self._heap = []
        self._removed = set()

    def push(self, task):
        heapq.heappush(self._heap, task)

    def remove(self, task):
        self._removed.add(task)  # mark as removed

    def pop(self):
        while self._heap:
            task = heapq.heappop(self._heap)
            if task not in self._removed:
                return task
        return None

lh = LazyHeap()
for t in [5, 1, 8, 3, 2]:
    lh.push(t)
lh.remove(1)  # 'delete' 1 lazily
lh.remove(8)  # 'delete' 8 lazily
results = [lh.pop() for _ in range(3)]
print(results)  # [2, 3, 5] -- 1 and 8 skipped

K-größtes Element in einem Datenstrom

K-größtes Element in einem Datenstrom (LeetCode #703) verwaltet einen Min-Heap der Größe k. Die Wurzel des Heaps ist stets das k-größte bisher gesehene Element. Wenn eine neue Zahl eintrifft, fügen Sie sie ein. Überschreitet der Heap anschließend die Größe k, entfernen Sie das Minimum. Die Wurzel ist immer das k-größte Element, weil es im Heap genau k-1 größere Elemente gibt.

import heapq

class KthLargest:
    def __init__(self, k, nums):
        self.k = k
        self.heap = []
        for num in nums:
            self.add(num)

    def add(self, val):
        heapq.heappush(self.heap, val)
        if len(self.heap) > self.k:
            heapq.heappop(self.heap)  # remove smallest
        return self.heap[0]  # kth largest = root of min-heap

# k=3, initial=[4,5,8,2]
kl = KthLargest(3, [4, 5, 8, 2])
print(kl.add(3))   # 4 (top 3: 8,5,4 -- kth=4)
print(kl.add(5))   # 5 (top 3: 8,5,5 -- kth=5)
print(kl.add(10))  # 5 (top 3: 10,8,5 -- kth=5)
print(kl.add(9))   # 8 (top 3: 10,9,8 -- kth=8)

K Paare mit der kleinsten Summe finden

K Paare mit den kleinsten Summen finden (LeetCode #373) verwendet einen Min-Heap, um Paare in sortierter Reihenfolge zu erzeugen. Beginnen Sie mit allen Paaren (nums1[0], nums2[j]) für jedes j. Entfernen Sie das Minimum und fügen Sie für das entfernte Paar (nums1[i], nums2[j]) das Paar (nums1[i+1], nums2[j]) ein – den nächsten Kandidaten aus derselben nums2-Spalte. Dies ist ein häufig verwendetes Muster zum Erzeugen geordneter Paare oder Produkte mit einem Heap.

import heapq

def k_smallest_pairs(nums1, nums2, k):
    if not nums1 or not nums2:
        return []
    heap = []
    # Initialize with pairs (nums1[0], nums2[j])
    for j in range(min(k, len(nums2))):
        heapq.heappush(heap, (nums1[0] + nums2[j], 0, j))
    result = []
    while heap and len(result) < k:
        total, i, j = heapq.heappop(heap)
        result.append([nums1[i], nums2[j]])
        if i + 1 < len(nums1):
            heapq.heappush(heap, (nums1[i+1] + nums2[j], i+1, j))
    return result

print(k_smallest_pairs([1,7,11], [2,4,6], 3))
# [[1,2], [1,4], [1,6]]

Aufgabenplaner mit einem Max-Heap

Task Scheduler (LeetCode #621) fragt nach der minimalen Zeit zum Planen von n Aufgaben mit einer Abkühlzeit von n Intervallen zwischen gleichen Aufgaben. Verwenden Sie einen Max-Heap mit den Aufgabenhäufigkeiten: Wählen Sie in jedem Zeitschritt die häufigste verfügbare Aufgabe aus, verringern Sie ihre Anzahl und setzen Sie sie auf Abkühlung. Verarbeiten Sie pro Zyklus k=n+1 Aufgaben oder füllen Sie die verbleibende Zeit mit Leerlauf. Dieser Greedy-Ansatz mit einem Max-Heap liefert die optimale Lösung.

import heapq
from collections import Counter

def least_interval(tasks, n):
    freq = Counter(tasks)
    heap = [-f for f in freq.values()]  # max-heap (negated)
    heapq.heapify(heap)
    time = 0
    while heap:
        cycle = n + 1
        temp = []
        for _ in range(cycle):
            if heap:
                temp.append(heapq.heappop(heap))
        for f in temp:
            if f + 1 < 0:  # still tasks remaining
                heapq.heappush(heap, f + 1)
        # Add full cycle or remaining tasks if queue empty
        time += cycle if heap else len(temp)
    return time

print(least_interval(['A','A','A','B','B','B'], 2))  # 8
print(least_interval(['A','A','A','B','B','B'], 0))  # 6

Heap im Dijkstra-Algorithmus

Die Prioritätswarteschlange im Dijkstra-Algorithmus wird mit einem Min-Heap implementiert. Speichern Sie Tupel (distance, node) und verarbeiten Sie immer zuerst den noch nicht besuchten Knoten mit der kürzesten Entfernung. Wenn Sie einen Knoten mit einer Entfernung entfernen, die größer ist als sein aktuell bekannter kürzester Pfad, überspringen Sie ihn. Dabei handelt es sich um einen veralteten Eintrag aus der Lazy Deletion. So benötigen Sie keine decrease-key-Operation, und die Implementierung bleibt einfach, während die Komplexität O((V + E) log V) erhalten bleibt.

import heapq

def dijkstra(graph, start):
    dist = {node: float('inf') for node in graph}
    dist[start] = 0
    heap = [(0, start)]  # (distance, node)
    while heap:
        d, u = heapq.heappop(heap)
        if d > dist[u]:   # stale entry, skip
            continue
        for v, w in graph[u]:
            if dist[u] + w < dist[v]:
                dist[v] = dist[u] + w
                heapq.heappush(heap, (dist[v], v))
    return dist

graph = {
    'A': [('B', 4), ('C', 1)],
    'B': [('D', 1)],
    'C': [('B', 2), ('D', 5)],
    'D': []
}
print(dijkstra(graph, 'A'))  # {'A':0,'B':3,'C':1,'D':4}

String mit einem Max-Heap umorganisieren

String umorganisieren (LeetCode #767) verlangt, einen String so umzuordnen, dass keine zwei benachbarten Zeichen gleich sind. Verwenden Sie einen Max-Heap aus (-frequency, char). Entfernen Sie in jedem Schritt das häufigste Zeichen. Wenn das vorherige Zeichen mit dem häufigsten Zeichen übereinstimmt, entfernen Sie stattdessen das zweithäufigste. Dieser Greedy-Ansatz stellt sicher, dass das am stärksten eingeschränkte Zeichen so früh wie möglich platziert wird.

import heapq
from collections import Counter

def reorganize_string(s):
    freq = Counter(s)
    heap = [(-f, c) for c, f in freq.items()]
    heapq.heapify(heap)
    result = []
    prev_freq, prev_char = 0, ''
    while heap:
        freq, char = heapq.heappop(heap)
        result.append(char)
        # Push back the previous character if still remaining
        if prev_freq < 0:
            heapq.heappush(heap, (prev_freq, prev_char))
        prev_freq, prev_char = freq + 1, char  # decrement freq (less negative)
    result_str = ''.join(result)
    # Verify no adjacent duplicates
    return result_str if len(result_str) == len(s) else ''

print(reorganize_string('aab'))   # 'aba'
print(reorganize_string('aaab'))  # '' (impossible)

Schnelltest

Testen Sie Ihr Verständnis der Konzepte aus Data Structures & Algorithms — Coding Interview Prep, die in dieser Lektion behandelt wurden.

Zusammenfassung der Lektion

In dieser Lektion haben Sie Folgendes gelernt: die API von Pythons heapq-Modul einschließlich heapify, heappush, heappop, nlargest, nsmallest und merge, die Simulation eines Max-Heaps durch Negieren von Werten sowie häufige Heap-Muster in Interviews wie Top-k-Streaming, das k-größte Element in einem Datenstrom, Aufgabenplanung und Dijkstra. Als Nächstes beschäftigen Sie sich mit dem Median aus einem Datenstrom und dem k-Wege-Merge.

Häufig gestellte Fragen

Ist die Lektion „Python heapq und Tricks für Max-Heaps“ kostenlos?

Ja — der vollständige Text von „Python heapq und Tricks für Max-Heaps“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des DSA Interview Prep-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der DSA Interview Prep-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Python heapq und Tricks für Max-Heaps“?

Verwenden Sie heapq.heappush/heappop, negieren Sie Werte zur Simulation eines Max-Heaps und wenden Sie heapq.nlargest/nsmallest für schnelle Top-k-Abfragen an. Du übst DSA Interview Prep mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um DSA Interview Prep zu starten?

Keine Vorkenntnisse erforderlich. DSA Interview Prep auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.

Wie lange dauert die Lektion „Python heapq und Tricks für Max-Heaps“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser DSA Interview Prep-Lektion Code schreiben und ausführen?

Ja. Jede DSA Interview Prep-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Heap-Eigenschaft und Array-Darstellung
  2. Heapify, Push und Pop von Grund auf
  3. Python heapq und Tricks für Max-Heaps
  4. Median aus einem Datenstrom und K-Wege-Merge
← Zurück zu DSA Interview Prep