Partition Equal Subset Sum
Formulieren Sie das Partitionsproblem als 0/1-Rucksackproblem mit dem Ziel total-sum/2 um und prüfen Sie die Machbarkeit mit einem booleschen DP-Array.
Partition Equal Subset Sum ist eine kostenlose Coding 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 Coding Interview Prep-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Coding Interview Prep-Kurs umfasst insgesamt 4 Lektionen.
Aufgabenstellung
Gegeben sei ein nichtleeres Array positiver Ganzzahlen nums. Bestimmen Sie, ob Sie es in zwei Teilmengen mit gleicher Summe aufteilen können. Beispielsweise kann [1, 5, 11, 5] in [1, 5, 5] und [11] aufgeteilt werden; beide Summen betragen 11. Wenn die Gesamtsumme ungerade ist, lautet die Antwort sofort False. Andernfalls müssen wir eine Teilmenge finden, deren Summe total_sum // 2 beträgt — ein klassisches Subset-Sum-Problem.
Reduktion auf Subset Sum
Die entscheidende Reduktion: Wenn die Gesamtsumme S gerade ist und eine Teilmenge die Summe S//2 ergibt, summieren sich die verbleibenden Elemente automatisch ebenfalls zu S//2. Daher reduziert sich Partition Equal Subset Sum auf die Frage: Ergibt die Summe irgendeiner Teilmenge von nums S//2? Dies ist das klassische NP-vollständige Problem Subset Sum, das wir mit 0/1-Rucksack-DP in einer Laufzeit von O(n × S) lösen.
def canPartition(nums):
total = sum(nums)
if total % 2 != 0:
return False # odd sum: impossible
target = total // 2
# Now: does any subset of nums sum to target?Boolesches DP-Array
Definieren Sie ein boolesches Array dp[c], wobei dp[c] = True bedeutet, dass eine Teilmenge mit genau der Summe c existiert. Initialisieren Sie dp[0] = True (die leere Teilmenge hat die Summe 0) und alle anderen Werte mit False. Iterieren Sie für jede Zahl num die Kapazität von target abwärts bis num (Rückwärtsiteration beim 0/1-Rucksackproblem) und setzen Sie dp[c] = dp[c] or dp[c - num].
def canPartition(nums):
total = sum(nums)
if total % 2 != 0:
return False
target = total // 2
dp = [False] * (target + 1)
dp[0] = True
for num in nums:
for c in range(target, num - 1, -1): # backward: 0/1 knapsack
dp[c] = dp[c] or dp[c - num]
return dp[target]
print(canPartition([1, 5, 11, 5])) # True
print(canPartition([1, 2, 3, 5])) # FalseDas Beispiel Schritt für Schritt verfolgen
Für [1, 5, 11, 5] gilt: total=22 und target=11. Zu Beginn ist dp[0]=True. Nach num=1: dp[1]=True. Nach num=5: dp[5]=True, dp[6]=True. Nach num=11: dp[11]=True (unter Verwendung der einzelnen 11). Wir haben bereits dp[11]=True gefunden, verarbeiten aber weiterhin alle Zahlen. Endergebnis: dp[11]=True, daher ist eine Aufteilung möglich.
Optimierung durch vorzeitigen Abbruch
Wir können einen vorzeitigen Abbruch einbauen: Sobald dp[target] den Wert True annimmt, geben wir sofort True zurück. Das kann die Best-Case-Szenarien erheblich beschleunigen. Wenn außerdem ein einzelnes Element target entspricht, können wir ebenfalls sofort True zurückgeben. Ist ein einzelnes Element größer als target, kann es nicht in einer Teilmenge enthalten sein, deren Summe target ergibt; die übrigen Elemente müssen wir jedoch weiterhin prüfen.
def canPartition_fast(nums):
total = sum(nums)
if total % 2 != 0:
return False
target = total // 2
if max(nums) > target: # any element > target makes it impossible
return False
dp = [False] * (target + 1)
dp[0] = True
for num in nums:
for c in range(target, num - 1, -1):
dp[c] = dp[c] or dp[c - num]
if dp[target]:
return True # early exit
return dp[target]
print(canPartition_fast([1, 5, 11, 5])) # TrueEine Python-Menge statt eines DP-Arrays verwenden
Eine Alternative besteht darin, eine Menge erreichbarer Summen zu verwalten. Beginnen Sie mit {0}. Fügen Sie für jede Zahl zu jeder Summe der aktuellen Menge die Zahl hinzu: reachable = reachable | {s + num for s in reachable}. Filtern Sie anschließend alle Summen heraus, die target überschreiten. Prüfen Sie am Ende, ob target in der Menge enthalten ist. Dieser Ansatz ist intuitiv, kann aber mehr Speicher benötigen und in der Praxis langsamer sein.
def canPartition_set(nums):
total = sum(nums)
if total % 2 != 0:
return False
target = total // 2
reachable = {0}
for num in nums:
reachable = {s + num for s in reachable if s + num <= target} | reachable
return target in reachable
print(canPartition_set([1, 5, 11, 5])) # TrueKomplexitätsanalyse
Der DP-Ansatz benötigt eine Laufzeit von O(n × S), wobei S = sum(nums) gilt, und verwendet O(S) Speicherplatz für das boolesche Array. Für die Einschränkungen bei LeetCode (n ≤ 200, sum ≤ 20.000) sind das höchstens 4.000.000 Operationen – sehr schnell. Der Mengenansatz hat dieselbe asymptotische Komplexität, kann in der Praxis aber aufgrund des Aufwands für die Mengenerstellung langsamer sein.
Verallgemeinerung: Teilmengen mit einer bestimmten Summe zählen
Ein verwandtes Problem besteht darin, die Anzahl der Teilmengen zu zählen, deren Summe einem Zielwert entspricht. Ändern Sie den DP von booleschen Werten zu Ganzzahlen: dp[c] = number of ways to reach sum c. Verwenden Sie statt OR eine Addition: dp[c] += dp[c - num]. Initialisieren Sie dp[0] = 1. Die Rückwärtsiteration bleibt unverändert. Diese Verallgemeinerung zeigt, wie sich das Rucksack-Template an unterschiedliche Fragen zu Teilmengen anpassen lässt.
def count_subsets(nums, target):
dp = [0] * (target + 1)
dp[0] = 1
for num in nums:
for c in range(target, num - 1, -1):
dp[c] += dp[c - num]
return dp[target]
print(count_subsets([1, 1, 1, 1, 1], 3)) # 10 (C(5,3))Häufige Rückfragen im Vorstellungsgespräch
Rechnen Sie mit folgenden Rückfragen: (1) Was ist, wenn Sie die tatsächliche Aufteilung zurückgeben müssen? – Dafür ist ein 2D-DP zur Rekonstruktion erforderlich. (2) Was ist, wenn Elemente negativ sein können? – Verschieben Sie das Ziel oder verwenden Sie statt eines Arrays ein Dictionary. (3) Wie hoch ist die Zeitkomplexität? – O(n × sum). (4) Können Sie die Lösung verbessern, wenn viele Zahlen gleich sind? – Ja, verwenden Sie eine Häufigkeitszählung, um die Anzahl der äußeren Iterationen zu reduzieren. Erwähnen Sie diese Abwägungen stets proaktiv.
Verbindung zum 0/1-Rucksackproblem
Partition Equal Subset Sum ist eine direkte Anwendung des 0/1-Rucksackproblems: Die Elemente sind die Zahlen, die Gewichte entsprechen den Werten und die Rucksackkapazität entspricht target. Wir prüfen, ob der maximale Wert target entspricht (Machbarkeit), und nicht, wie hoch der maximale Wert ist. Die Rückwärtsiteration ist identisch; lediglich die Operation ändert sich von max zu einem booleschen or. Diese Verbindung in einem Vorstellungsgespräch zu erkennen, zeigt ein ausgeprägtes Erkennen von Mustern.
Sonderfälle
Folgende Sonderfälle müssen Sie berücksichtigen: (1) Array der Länge 1 – ein einzelnes Element kann nicht aufgeteilt werden, daher immer False; (2) alle Elemente identisch und ihre Anzahl gerade – das Ergebnis hängt von den einzelnen Werten ab; (3) sehr große Summen – prüfen Sie die Einschränkungen, bevor Sie das DP-Array anlegen; (4) Elemente, die größer als target sind – sie können übersprungen werden, da sie niemals Teil einer Teilmenge mit der Summe target sein können. Die Prüfung des größten Elements als vorzeitiger Abbruch behandelt Fall (4) effizient.
Kurzer Test
Testen Sie Ihr Verständnis der Konzepte aus Data Structures & Algorithms — Coding Interview Prep aus dieser Lektion.
Zusammenfassung der Lektion
In dieser Lektion haben Sie gelernt: Partition Equal Subset Sum reduziert sich auf Subset Sum mit target = total//2, der eindimensionale boolesche DP dp[c] verwendet dieselbe Rückwärtsiteration wie das 0/1-Rucksackproblem und der Ansatz lässt sich auf das Zählen von Teilmengen verallgemeinern, indem boolesches OR durch eine Ganzzahladdition ersetzt wird. Als Nächstes behandeln wir Target Sum und wandeln die Vorzeichenbelegung in ein Rucksackproblem über Teilmengensummendifferenzen um.
Häufig gestellte Fragen
Ist die Lektion „Partition Equal Subset Sum“ kostenlos?
Ja — der vollständige Text von „Partition Equal Subset Sum“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Coding Interview Prep-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Coding Interview Prep-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Partition Equal Subset Sum“?
Formulieren Sie das Partitionsproblem als 0/1-Rucksackproblem mit dem Ziel total-sum/2 um und prüfen Sie die Machbarkeit mit einem booleschen DP-Array. Du übst Coding 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 Coding Interview Prep zu starten?
Keine Vorkenntnisse erforderlich. Coding 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 „Partition Equal Subset Sum“?
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 Coding Interview Prep-Lektion Code schreiben und ausführen?
Ja. Jede Coding 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
- 0/1-Rucksack und Speicheroptimierung
- Unbeschränkter Rucksack und Coin Change II
- Partition Equal Subset Sum
- Zielsumme mit positiven und negativen Vorzeichen