Voorbereiding op programmeerinterviews · Les

Partition Equal Subset Sum

Herformuleer het partition-probleem als een 0/1-knapsack met als doel total-sum/2 en bepaal de haalbaarheid met een booleaanse DP-array.

Les 3 van 413 stappen

Partition Equal Subset Sum is een gratis Voorbereiding op programmeerinterviews-les op CoddyKit. Dit is les 3 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Voorbereiding op programmeerinterviews. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Voorbereiding op programmeerinterviews bevat in totaal 4 lessen.

Probleembeschrijving

Gegeven een niet-lege array met positieve gehele getallen nums, bepaal je of je deze kunt verdelen in twee deelverzamelingen met gelijke som. Zo kan [1, 5, 11, 5] bijvoorbeeld worden verdeeld in [1, 5, 5] en [11], die allebei optellen tot 11. Als de totale som oneven is, is het antwoord meteen False. Anders moeten we een deelverzameling vinden waarvan de som gelijk is aan total_sum // 2 — een klassiek deelverzamelingensomprobleem.

Herleiding naar de som van een deelverzameling

De belangrijkste herleiding: als de totale som S even is en een deelverzameling optelt tot S//2, tellen de overgebleven elementen automatisch ook op tot S//2. Dus het probleem van gelijke sommen van deelverzamelingen reduceert tot de vraag: telt een deelverzameling van nums op tot S//2? Dit is het klassieke NP-volledige probleem van de som van een deelverzameling, dat we oplossen met dynamische programmering voor het 0/1-rugzakprobleem in O(n × S)-tijd.

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?

Booleaanse DP-array

Definieer een booleaanse array dp[c], waarbij dp[c] = True betekent dat er een deelverzameling bestaat met een som van precies c. Initialiseer dp[0] = True (de lege deelverzameling heeft som 0) en alle andere waarden met False. Doorloop voor elk getal num de capaciteit van target omlaag tot num (achterwaartse iteratie bij het 0/1-rugzakprobleem) en stel dp[c] = dp[c] or dp[c - num] in.

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]))   # False

Het voorbeeld stap voor stap doorlopen

Voor [1, 5, 11, 5] geldt total=22 en target=11. Aanvankelijk is dp[0]=True. Na num=1: dp[1]=True. Na num=5: dp[5]=True, dp[6]=True. Na num=11: dp[11]=True (waarbij alleen 11 wordt gebruikt). We hebben dp[11]=True al gevonden, maar we blijven alle getallen verwerken. Het uiteindelijke antwoord is: dp[11]=True, dus een partitie is mogelijk.

Optimalisatie door vroegtijdig stoppen

We kunnen een vroegtijdige stop toevoegen: als dp[target] op enig moment True wordt, geef dan onmiddellijk True terug. Dit kan scenario's waarin het doel snel wordt bereikt aanzienlijk versnellen. Als één afzonderlijk element gelijk is aan target, kunnen we ook meteen True teruggeven. Als één afzonderlijk element groter is dan target, kan het geen deel uitmaken van een deelverzameling met som target, maar we moeten de rest nog steeds controleren.

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]))  # True

Een Python-set gebruiken in plaats van een DP-array

Een alternatief is om een verzameling bereikbare sommen bij te houden. Begin met {0}. Voeg voor elk getal het getal toe aan elke som in de huidige verzameling: reachable = reachable | {s + num for s in reachable}. Filter de waarden zodat alleen sommen overblijven die target niet overschrijden. Controleer aan het einde of target in de verzameling zit. Deze aanpak is intuïtief, maar kan meer geheugen gebruiken en in de praktijk trager zijn.

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]))  # True

Complexiteitsanalyse

De DP-aanpak werkt in O(n × S)-tijd, waarbij S = sum(nums), en gebruikt O(S)-ruimte voor de booleaanse array. Voor de beperkingen van LeetCode (n ≤ 200, sum ≤ 20.000) zijn dat hoogstens 4.000.000 bewerkingen — zeer snel. De verzamelingsaanpak heeft dezelfde asymptotische complexiteit, maar kan in de praktijk trager zijn door het extra werk voor het opbouwen van verzamelingen.

Generaliseren: deelverzamelingen met een bepaalde som tellen

Een verwant probleem is het tellen van het aantal deelverzamelingen met een bepaalde doelwaarde. Verander de DP van booleaans naar een geheel getal: dp[c] = number of ways to reach sum c. Gebruik optellen in plaats van OR: dp[c] += dp[c - num]. Initialiseer dp[0] = 1. Gebruik dezelfde achterwaartse iteratie. Deze generalisatie laat zien hoe het rugzaksjabloon zich aanpast aan verschillende vragen over deelverzamelingen.

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))

Veelvoorkomende vervolgvragen in sollicitatiegesprekken

Verwacht vervolgvragen zoals: (1) Wat als je de daadwerkelijke partitie moet teruggeven? — daarvoor is 2D-DP voor reconstructie nodig. (2) Wat als elementen negatief mogen zijn? — verschuif target of gebruik een woordenboek in plaats van een array. (3) Wat is de tijdcomplexiteit? — O(n × sum). (4) Kun je de aanpak verbeteren als veel getallen hetzelfde zijn? — ja, gebruik frequentietellingen om het aantal buitenste iteraties te verminderen. Benoem deze afwegingen altijd uit jezelf.

De koppeling met het 0/1-rugzakprobleem

Het probleem van gelijke sommen van deelverzamelingen is een directe toepassing van het 0/1-rugzakprobleem: de getallen zijn de objecten, de gewichten zijn gelijk aan de waarden en de capaciteit van de rugzak is gelijk aan target. We vragen of de maximale waarde gelijk is aan target (haalbaarheid), niet wat de maximale waarde is. De achterwaartse iteratie is hetzelfde; alleen de bewerking verandert van max in de booleaanse bewerking or. Als je dit verband tijdens een sollicitatiegesprek herkent, laat dat zien dat je patronen goed kunt herkennen.

Randgevallen

Verwerk de volgende randgevallen: (1) array met lengte 1 — één element kan niet worden opgesplitst, dus het resultaat is altijd False; (2) alle elementen zijn gelijk en het aantal elementen is even — dit kan afhankelijk van de afzonderlijke waarden wel of niet werken; (3) zeer grote sommen — controleer de beperkingen voordat je de DP-array toewijst; (4) elementen die groter zijn dan target — deze kun je overslaan, omdat ze nooit deel kunnen uitmaken van een deelverzameling met som target. De controle van het grootste element als vroegtijdige stop verwerkt geval (4) efficiënt.

Korte controle

Toets je begrip van de concepten uit Data Structures & Algorithms — Coding Interview Prep in deze les.

Samenvatting van de les

In deze les heb je geleerd: het probleem van gelijke sommen van deelverzamelingen reduceert tot het probleem van een deelverzamelingssom met target = total//2, de booleaanse 1D-DP dp[c] gebruikt achterwaartse iteratie, net als het 0/1-rugzakprobleem, en je kunt de aanpak uitbreiden naar het tellen van deelverzamelingen door booleaanse OR te vervangen door optellen van gehele getallen. Hierna behandelen we het probleem van de doelsom, waarbij teken toewijzen wordt omgezet in een rugzakprobleem op basis van verschillen tussen deelverzamelingssommen.

Gratis beginnen

Leer Voorbereiding op programmeerinterviews met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
90
Lessen
360

Veelgestelde vragen

Is de les “Partition Equal Subset Sum” gratis?

Ja — de volledige tekst van “Partition Equal Subset Sum” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus Voorbereiding op programmeerinterviews wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus Voorbereiding op programmeerinterviews bevat in totaal 4 lessen.

Wat leer ik in “Partition Equal Subset Sum”?

Herformuleer het partition-probleem als een 0/1-knapsack met als doel total-sum/2 en bepaal de haalbaarheid met een booleaanse DP-array. Je oefent met Voorbereiding op programmeerinterviews door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met Voorbereiding op programmeerinterviews te beginnen?

Ervaring vooraf is niet nodig. Voorbereiding op programmeerinterviews op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 3 van 4.

Hoe lang duurt de les “Partition Equal Subset Sum”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over Voorbereiding op programmeerinterviews?

Ja. Elke les over Voorbereiding op programmeerinterviews bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. 0/1 Knapsack en ruimteoptimalisatie
  2. Unbounded Knapsack en Coin Change II
  3. Partition Equal Subset Sum
  4. Target Sum met positieve en negatieve tekens
← Terug naar Voorbereiding op programmeerinterviews