Permutationer och kombinationer
Enumerera alla permutationer av en lista, både med och utan dubblettelement, och generera alla k-kombinationer samt varianter av kombinationssummor.
Permutationer och kombinationer är en gratis lektion i Förberedelse inför kodningsintervjuer på CoddyKit. Detta är lektion 3 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Förberedelse inför kodningsintervjuer, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Förberedelse inför kodningsintervjuer innehåller totalt 4 lektioner.
Permutationer kontra kombinationer
Permutationer är arrangemang där ordningen spelar roll: [1,2,3] och [3,2,1] är olika. Antalet permutationer av n element är n!. Kombinationer är urval där ordningen inte spelar någon roll: att välja {1,2} är samma sak som att välja {2,1}. Antalet k-kombinationer från n element är C(n,k) = n! / (k! × (n-k)!). Båda är viktiga mönster i intervjuproblem om att räkna, räkna upp och välja.
import math
# Permutations
n = 4
print(f'Permutations of {n} items: {math.factorial(n)}')
# 4! = 24
# Combinations
for k in range(n+1):
print(f'C({n},{k}) = {math.comb(n,k)}')
# C(4,0)=1, C(4,1)=4, C(4,2)=6, C(4,3)=4, C(4,4)=1
# Sum = 2^4 = 16 (total subsets)Generera alla permutationer
Använd en boolesk array used för att hålla reda på vilka element som ingår i den aktuella vägen. Försök vid varje steg med alla oanvända element. När utforskningen är klar markerar ni elementet som oanvänt igen. Till skillnad från delmängder finns inget start-index, eftersom permutationer använder elementen i valfri ordning. Rekursionen avslutas när len(path) == n.
def permutations(nums):
result = []
used = [False] * len(nums)
def backtrack(path):
if len(path) == len(nums):
result.append(list(path))
return
for i, num in enumerate(nums):
if not used[i]:
used[i] = True # CHOOSE
path.append(num)
backtrack(path) # EXPLORE
path.pop() # UNCHOOSE
used[i] = False
backtrack([])
return result
print(permutations([1, 2, 3]))
# [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]Permutationer med byte
Ett alternativ är att byta elementet på position start med varje element från start till n-1, göra ett rekursivt anrop och sedan byta tillbaka. Detta ändrar arrayen på plats utan en used-array. Kärninsikten är att allt till vänster om start är fixerat på varje nivå, och att vi väljer vilket element som ska placeras på position start. Metoden använder något mindre minne och ligger till grund för Heap-algoritmen.
def permutations_swap(nums):
result = []
def backtrack(start):
if start == len(nums):
result.append(list(nums))
return
for i in range(start, len(nums)):
nums[start], nums[i] = nums[i], nums[start] # CHOOSE (swap)
backtrack(start + 1) # EXPLORE
nums[start], nums[i] = nums[i], nums[start] # UNCHOOSE (swap back)
backtrack(0)
return result
print(permutations_swap([1, 2, 3]))
# Same 6 permutations, different orderPermutationer II: Hantera dubbletter
När indata innehåller dubbletter, till exempel [1, 1, 2], genererar metoden med en used-array dubbletter av permutationerna. Åtgärd: sortera arrayen och hoppa över en dubblett om det föregående identiska elementet inte har använts i detta rekursiva anrop. Villkoret är: if i > 0 and nums[i] == nums[i-1] and not used[i-1]: continue. Detta tvingar fram att dubbletter alltid väljs från vänster till höger.
def permutations_unique(nums):
nums.sort()
result = []
used = [False] * len(nums)
def backtrack(path):
if len(path) == len(nums):
result.append(list(path))
return
for i in range(len(nums)):
if used[i]: continue
# Skip if this num is a duplicate and the previous dup was not used
if i > 0 and nums[i] == nums[i-1] and not used[i-1]:
continue
used[i] = True
path.append(nums[i])
backtrack(path)
path.pop()
used[i] = False
backtrack([])
return result
print(permutations_unique([1, 1, 2]))
# [[1,1,2],[1,2,1],[2,1,1]] — 3, not 6Nästa permutation (lexikografisk)
Next Permutation (LeetCode 31) omvandlar en array till dess nästa lexikografiskt större permutation på plats. Algoritmen är: (1) Hitta det index i längst till höger där nums[i] < nums[i+1]. (2) Hitta det index j längst till höger där nums[j] > nums[i]. (3) Byt plats på nums[i] och nums[j]. (4) Vänd på suffixet efter index i. Om inget sådant i finns vänder ni på hela arrayen, vilket går runt till den minsta permutationen.
def next_permutation(nums):
n = len(nums)
# Step 1: find rightmost i where nums[i] < nums[i+1]
i = n - 2
while i >= 0 and nums[i] >= nums[i+1]:
i -= 1
if i >= 0:
# Step 2: find rightmost j where nums[j] > nums[i]
j = n - 1
while nums[j] <= nums[i]:
j -= 1
# Step 3: swap
nums[i], nums[j] = nums[j], nums[i]
# Step 4: reverse suffix after i
nums[i+1:] = nums[i+1:][::-1]
return nums
print(next_permutation([1, 2, 3])) # [1,3,2]
print(next_permutation([3, 2, 1])) # [1,2,3] (wraps)
print(next_permutation([1, 1, 5])) # [1,5,1]Backtracking för k-kombinationer
Generera alla kombinationer av k element från n (LeetCode 77). Använd ett startindex, som för delmängder, för att undvika att besöka element igen och bevara sorterad ordning. Beskär när färre än k - len(path) element återstår: if len(nums) - i + 1 < k - len(path): break. Detta motsvarar den tidigare combine(n, k), men med en faktisk array som indata.
def combinations(nums, k):
result = []
def backtrack(start, path):
if len(path) == k:
result.append(list(path))
return
for i in range(start, len(nums)):
# Pruning: not enough elements left
if len(nums) - i < k - len(path):
break
path.append(nums[i])
backtrack(i + 1, path)
path.pop()
backtrack(0, [])
return result
print(combinations([1,2,3,4,5], 3))
# 10 combinations: C(5,3)
import math
print(math.comb(5,3)) # 10Combination Sum: obegränsad återanvändning
Combination Sum (LeetCode 39) tillåter att varje tal används ett obegränsat antal gånger. Skillnaden mot vanliga kombinationer är att ni, i stället för att flytta start till i+1, skickar vidare i (samma index) för att kunna återanvända det aktuella elementet. Beskärning: om det återstående målvärdet blir 0 sparar ni den aktuella vägen; om det blir negativt avbryter ni. Sortering gör det möjligt att avsluta tidigt när alla återstående kandidater är större än det återstående målvärdet.
def combination_sum(candidates, target):
candidates.sort()
result = []
def backtrack(start, path, remaining):
if remaining == 0:
result.append(list(path))
return
for i in range(start, len(candidates)):
c = candidates[i]
if c > remaining: break # all remaining are too big
path.append(c)
backtrack(i, path, remaining - c) # reuse allowed: pass i, not i+1
path.pop()
backtrack(0, [], target)
return result
print(combination_sum([2, 3, 6, 7], 7))
# [[2,2,3],[7]]Combination Sum II: ingen återanvändning, med dubbletter
Combination Sum II (LeetCode 40) använder varje tal högst en gång, men indata kan innehålla dubbletter. Metoden kombinerar två tekniker: flytta start till i+1 (ingen återanvändning) och hoppa över dubbletter på samma nivå (if i > start and nums[i] == nums[i-1]: continue) efter sortering. Detta förenar dubbletthanteringen från Subsets II med begränsningen att element inte får återanvändas från Combinations.
def combination_sum_ii(candidates, target):
candidates.sort()
result = []
def backtrack(start, path, remaining):
if remaining == 0:
result.append(list(path))
return
for i in range(start, len(candidates)):
if candidates[i] > remaining: break
# Skip duplicates at same level
if i > start and candidates[i] == candidates[i-1]:
continue
path.append(candidates[i])
backtrack(i + 1, path, remaining - candidates[i]) # no reuse: i+1
path.pop()
backtrack(0, [], target)
return result
print(combination_sum_ii([10,1,2,7,6,1,5], 8))
# [[1,1,6],[1,2,5],[1,7],[2,6]]Bokstavskombinationer för telefonnummer
Letter Combinations (LeetCode 17) kopplar varje siffra till bokstäverna på en telefonknappsats och genererar alla möjliga bokstavskombinationer för en given siffersträng. Detta är ett backtrackingproblem där vi vid varje position väljer en bokstav från den mappning som hör till siffran och går rekursivt vidare. För en sträng med längden n och i genomsnitt k bokstäver per siffra är tidskomplexiteten O(kⁿ).
def letter_combinations(digits):
if not digits: return []
phone = {
'2': 'abc', '3': 'def', '4': 'ghi', '5': 'jkl',
'6': 'mno', '7': 'pqrs', '8': 'tuv', '9': 'wxyz'
}
result = []
def backtrack(index, path):
if index == len(digits):
result.append(''.join(path))
return
for letter in phone[digits[index]]:
path.append(letter)
backtrack(index + 1, path)
path.pop()
backtrack(0, [])
return result
print(letter_combinations('23'))
# ['ad','ae','af','bd','be','bf','cd','ce','cf']Jämförelse mellan permutationer och kombinationer
De viktigaste strukturella skillnaderna är: Permutationer — inget startindex, använd en used-array eller byte för att undvika återanvändning, trädet har n val på varje nivå och totalt n! löv. Kombinationer — använd ett startindex för att upprätthålla ordningen, vilket ger C(n,k) löv. Combination Sum — flytta inte fram startindexet när element får återanvändas och beskär utifrån målvärdet. Om ni kopplar ett nytt problem till en av dessa tre former får ni rätt mall direkt.
# Pattern summary:
# Permutations: for i in range(n); if not used[i]; no start advancement
# Combinations: for i in range(start, n); advance start → i+1
# Combo Sum (reuse): for i in range(start, n); advance start → i (same)
# Quick reference:
import math
n = 5
print(f'Perm({n}) = n! = {math.factorial(n)}')
print(f'Comb({n},2) = C(n,k) = {math.comb(n,2)}')
print(f'Comb({n},3) = {math.comb(n,3)}')
# Also: subsets = sum(C(n,k) for k=0..n) = 2^n
print(f'Subsets({n}) = 2^n = {2**n}')Komplexitet och intervjutips
Tidskomplexiteten för uppräkning är: Permutationer O(n × n!), Kombinationer O(k × C(n,k)), Combination Sum O(n^(T/min_val)). Utrymmeskomplexiteten är O(n) för rekursionsdjupet plus O(output) för resultaten. Viktiga tips: (1) Klargör alltid om ordningen spelar roll (permutation eller kombination). (2) Nämn hanteringen av dubbletter innan ni blir tillfrågade. (3) Ange alltid beskärningsvillkoret uttryckligen. (4) För stora n bör ni påpeka att själva resultatet är exponentiellt — algoritmen är optimal för uppgiften.
import math
# Complexity for n=10
n = 10
print(f'Permutations(10): {math.factorial(n):,} results')
print(f'Combinations(10,5): {math.comb(n,5):,} results')
print(f'Subsets(10): {2**n:,} results')
# For interview: state which pattern
# 'This is a combinations problem because order doesnt matter'
# 'I will use a start index to avoid revisiting elements'
# 'Pruning: when sum exceeds target, break (after sorting)'Snabbtest
Testa er förståelse av begreppen i Data Structures & Algorithms — Coding Interview Prep från den här lektionen.
Sammanfattning av lektionen
I den här lektionen lärde ni er: permutationer använder en used-array och inget startindex, och genererar n! arrangemang, kombinationer använder ett startindex som flyttas fram för att undvika återanvändning, och genererar C(n,k)-urval, och dubbletter i båda problemen hanteras genom att sortera och hoppa över upprepade värden på samma rekursionsnivå. Härnäst tillämpar vi backtracking på N-Queens-problemet och utforskar propagering av begränsningar.
Lär dig Förberedelse inför kodningsintervjuer med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 90
- Lektioner
- 360
Vanliga frågor
Är lektionen ”Permutationer och kombinationer” gratis?
Ja – hela texten till ”Permutationer och kombinationer” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Förberedelse inför kodningsintervjuer, kan Ni uppgradera till CoddyKit PRO. Kursen i Förberedelse inför kodningsintervjuer innehåller totalt 4 lektioner.
Vad lär jag mig i ”Permutationer och kombinationer”?
Enumerera alla permutationer av en lista, både med och utan dubblettelement, och generera alla k-kombinationer samt varianter av kombinationssummor. Ni övar på Förberedelse inför kodningsintervjuer med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Förberedelse inför kodningsintervjuer?
Du behöver inga förkunskaper. Utbildningen i Förberedelse inför kodningsintervjuer på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 4.
Hur lång tid tar lektionen ”Permutationer och kombinationer”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Förberedelse inför kodningsintervjuer-lektionen?
Ja. Varje Förberedelse inför kodningsintervjuer-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Backtracking-mall: välj, utforska, välj bort
- Delmängder och potensmängd
- Permutationer och kombinationer
- N-drottningar och constraint propagation