Mal for splitt og hersk
Trekk ut malen i tre trinn (splitt, løs, kombiner) fra flettesortering, og bruk den systematisk på nye problemformer.
Mal for splitt og hersk er en gratis leksjon i DSA Interview Prep på CoddyKit. Dette er leksjon 1 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i DSA Interview Prep, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i DSA Interview Prep inneholder totalt 4 leksjoner.
Hva er Divide and Conquer?
Divide and Conquer (D&C) løser et problem ved å dele det opp i uavhengige delproblemer av samme type, løse hvert av dem rekursivt og kombinere løsningene. Nøkkelordet er uavhengige — delproblemene deler ikke tilstand (i motsetning til DP, der de overlapper). Klassiske eksempler er merge sort, binærsøk, quicksort, nærmeste punktpar og rask matrisemultiplikasjon. D&C oppnår vanligvis O(n log n)-tid ved hjelp av malen i tre trinn.
# Divide and Conquer vs DP:
# D&C: sub-problems are INDEPENDENT (no overlap)
# DP: sub-problems OVERLAP (same sub-problem solved multiple times)
# D&C examples:
# Merge sort: split array in half, sort each, merge
# Binary search: check midpoint, recurse on one half
# Max subarray (D&C): find max in left half, right half, crossing
# Recurrence pattern:
# T(n) = 2T(n/2) + O(n) → O(n log n) [merge sort]
# T(n) = T(n/2) + O(1) → O(log n) [binary search]
# T(n) = T(n/k) + O(n) → O(n log_k n) [k-way split]Malen i tre trinn
Alle D&C-algoritmer følger tre trinn: (1) Divide — del problemet i to (eller flere) mindre delproblemer, vanligvis ved midtpunktet. (2) Conquer — løs hvert delproblem rekursivt. Definer et basistilfelle som stopper rekursjonen (vanligvis n ≤ 1). (3) Combine — flett eller kombiner løsningene på delproblemene til den samlede løsningen. Kreativiteten ligger helt og holdent i Combine-trinnet; Divide består vanligvis bare av å dele ved midtpunktet.
def divide_and_conquer(arr, lo, hi):
# BASE CASE: trivial sub-problem
if lo >= hi:
return base_case_result(arr, lo, hi)
# DIVIDE: split at midpoint
mid = (lo + hi) // 2
# CONQUER: solve sub-problems recursively
left_result = divide_and_conquer(arr, lo, mid)
right_result = divide_and_conquer(arr, mid + 1, hi)
# COMBINE: merge results
return combine(left_result, right_result, arr, lo, mid, hi)
def base_case_result(arr, lo, hi): return arr[lo]
def combine(l, r, arr, lo, mid, hi): return max(l, r)Merge sort som det klassiske eksempelet
Merge sort illustrerer D&C perfekt: Divide arrayet ved midtpunktet. Conquer ved å sortere hver halvdel rekursivt. Combine ved å flette de to sorterte halvdelene i O(n). Det er i flettetrinnet alt arbeidet skjer. Rekurrens: T(n) = 2T(n/2) + O(n). Ved hjelp av Master Theorem, tilfelle 2: T(n) = O(n log n). Dette er den viktigste D&C-rekurrensen å lære utenat.
def merge_sort(arr):
# BASE CASE
if len(arr) <= 1:
return arr
# DIVIDE
mid = len(arr) // 2
# CONQUER
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])
# COMBINE
return merge(left, right)
def merge(left, right):
result = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i]); i += 1
else:
result.append(right[j]); j += 1
return result + left[i:] + right[j:]
print(merge_sort([5, 3, 8, 1, 9, 2])) # [1,2,3,5,8,9]Kort oppslagsverk for Master Theorem
Master Theorem løser rekurrenser på formen T(n) = aT(n/b) + f(n): Tilfelle 1: f(n) = O(n^(log_b(a) - ε)) → T(n) = O(n^log_b(a)). Tilfelle 2: f(n) = O(n^log_b(a)) → T(n) = O(n^log_b(a) × log n). Tilfelle 3: f(n) = Ω(n^(log_b(a) + ε)) → T(n) = O(f(n)). Merge sort: a=2, b=2, f(n)=O(n), n^log_2(2)=n → tilfelle 2 → O(n log n).
# Master Theorem quick examples:
# T(n) = 2T(n/2) + O(n) → a=2,b=2,f=n,n^log2(2)=n → Case2 → O(n log n)
# T(n) = 2T(n/2) + O(1) → a=2,b=2,f=1,n^1=n >> 1 → Case1 → O(n)
# T(n) = 2T(n/2) + O(n^2) → a=2,b=2,f=n^2,n^1 << n^2 → Case3 → O(n^2)
# T(n) = T(n/2) + O(1) → a=1,b=2,f=1,n^log2(1)=1=f → Case2 → O(log n)
# T(n) = T(n/3)+T(2n/3)+O(n) → Master doesn't apply directly → O(n log n) by recursion tree
recurrences = [
('Merge sort: 2T(n/2)+n', 'O(n log n)'),
('Binary search: T(n/2)+1', 'O(log n)'),
('Naive matrix mult: 8T(n/2)+n^2', 'O(n^3)'),
('Strassen: 7T(n/2)+n^2', 'O(n^2.81)'),
]
for r, sol in recurrences: print(r, '->', sol)Maksimalt delarray: D&C-tilnærming
D&C-tilnærmingen for maksimalt delarray er som følger: Svaret ligger enten helt i venstre halvdel, helt i høyre halvdel eller krysser midtpunktet. I tilfellet som krysser midtpunktet, utvides det mot venstre fra mid og mot høyre fra mid+1, og den største summen i hver retning tas med. Deretter kombineres resultatene. Denne D&C-løsningen med O(n log n) er tregere enn Kadane's med O(n), men viser malen på en tydelig måte og er et vanlig intervjuspørsmål om D&C.
def max_subarray_dc(nums, lo=None, hi=None):
if lo is None: lo, hi = 0, len(nums) - 1
if lo == hi: return nums[lo]
mid = (lo + hi) // 2
# Conquer
left_max = max_subarray_dc(nums, lo, mid)
right_max = max_subarray_dc(nums, mid + 1, hi)
# Cross-midpoint sum
left_sum = curr = 0
for i in range(mid, lo - 1, -1):
curr += nums[i]
left_sum = max(left_sum, curr)
right_sum = curr = 0
for i in range(mid + 1, hi + 1):
curr += nums[i]
right_sum = max(right_sum, curr)
cross_max = left_sum + right_sum
return max(left_max, right_max, cross_max)
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
print(max_subarray_dc(nums)) # 6Potensfunksjon: rask eksponentiering
Fast Power (LeetCode 50): beregn x^n i O(log n) ved hjelp av D&C. Hvis n er partall: x^n = (x^(n/2))^2. Hvis n er oddetall: x^n = x × x^(n-1). Håndter negativ n med x^(-n) = 1/x^n. Hvert rekursivt kall halverer n, så dybden er O(log n). Dette er et tydelig eksempel der Combine-trinnet bare er multiplikasjon — enkelt, men effektivt.
def my_pow(x, n):
if n < 0:
return 1 / my_pow(x, -n)
# BASE CASE
if n == 0: return 1
# DIVIDE and CONQUER
half = my_pow(x, n // 2)
if n % 2 == 0:
return half * half # even: x^n = (x^(n/2))^2
else:
return x * half * half # odd: x^n = x * (x^(n/2))^2
print(my_pow(2, 10)) # 1024
print(my_pow(2, -2)) # 0.25
print(my_pow(3, 5)) # 243
print(my_pow(0, 0)) # 1Sortert array til BST
Convert Sorted Array to BST (LeetCode 108) bruker D&C: velg midtpunktet som rot (slik at høyden blir balansert), bygg venstre undertre rekursivt fra venstre halvdel og høyre undertre fra høyre halvdel. Dette gir et høydebalansert BST med minimumshøyde O(log n). D&C-strukturen speiler binærsøk — hvert rekursjonsnivå tilordner midtpunktet som rot for det gjeldende delområdet.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def sorted_array_to_bst(nums):
def helper(lo, hi):
if lo > hi: return None
mid = (lo + hi) // 2
node = TreeNode(nums[mid]) # DIVIDE at midpoint
node.left = helper(lo, mid - 1) # CONQUER left
node.right = helper(mid + 1, hi) # CONQUER right
# COMBINE: already done by assignment
return node
return helper(0, len(nums) - 1)
def inorder(node):
if not node: return []
return inorder(node.left) + [node.val] + inorder(node.right)
root = sorted_array_to_bst([-10, -3, 0, 5, 9])
print(inorder(root)) # [-10,-3,0,5,9] (sorted, proving BST property)Når D&C ikke er det beste valget
D&C har ekstra kostnader: dybden på funksjonskallstakken, oppdeling av arrayet (hvis det ikke brukes indekser) og kombineringssteget. Det er optimalt når kombineringssteget er O(n) eller billigere. Når delproblemene overlapper, beregner D&C løsninger på nytt på en lite effektiv måte — da trengs DP. Når kombineringssteget dominerer (for eksempel O(n²)), gir D&C ingen forbedring sammenlignet med naive tilnærminger. Vær klar over når De bør velge hva: D&C for uavhengige delproblemer og DP for overlappende delproblemer.
# When D&C hurts:
# Fibonacci with pure D&C (no memo): T(n) = T(n-1) + T(n-2) → O(2^n)
# Sub-problems OVERLAP → use DP or memoisation instead
def fib_dc(n):
if n <= 1: return n
return fib_dc(n-1) + fib_dc(n-2) # O(2^n)!
def fib_dp(n):
a, b = 0, 1
for _ in range(n): a, b = b, a+b
return a # O(n)
print(fib_dp(30)) # fast
# fib_dc(40) would take seconds — do not run large values!D&C for binærsøk i sortert matrise
Søk i en 2D-matrise (LeetCode 240) der hver rad og kolonne er sortert, kan løses med D&C: start øverst til høyre. Hvis current > target, flytt til venstre (eliminerer kolonnen). Hvis current < target, flytt nedover (eliminerer raden). Hvis de er like, er elementet funnet. Denne algoritmen med O(m+n) er teknisk sett ikke rekursiv D&C, men deler den sentrale ideen: eliminer en del av søkeområdet for hvert steg.
def search_matrix(matrix, target):
if not matrix: return False
m, n = len(matrix), len(matrix[0])
row, col = 0, n - 1 # start top-right
while row < m and col >= 0:
val = matrix[row][col]
if val == target:
return True
elif val > target:
col -= 1 # eliminate this column
else:
row += 1 # eliminate this row
return False
matrix = [
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
print(search_matrix(matrix, 5)) # True
print(search_matrix(matrix, 20)) # FalseAnalyse med rekursjonstre
For D&C-rekurrenser som ikke passer med Master Theorem, kan De bruke metoden med rekursjonstre. Tegn hvert nivå av rekursive kall og summer arbeidet på hvert nivå. Merge sort: På nivå k finnes det 2^k delproblemer med størrelse n/2^k. Arbeid per nivå = 2^k × O(n/2^k) = O(n). Totalt antall nivåer = log n. Totalt arbeid = O(n log n). Denne visuelle metoden fungerer for enhver rekurrens og gir en intuitiv forståelse av hvorfor D&C vanligvis ender på O(n log n).
# Merge sort recursion tree analysis:
# Level 0: 1 problem of size n → O(n) work
# Level 1: 2 problems of size n/2 → 2*O(n/2) = O(n) work
# Level 2: 4 problems of size n/4 → 4*O(n/4) = O(n) work
# ...
# Level log(n): n problems of size 1 → n*O(1) = O(n) work
# Total levels = log(n)+1
# Total work = O(n) * O(log n) = O(n log n)
import math
n = 64
levels = int(math.log2(n)) + 1
print(f'n={n}: {levels} levels, {n}*{levels} = {n*levels} work units')
print(f'O(n log n) = O({n} * {int(math.log2(n))}) = O({n*int(math.log2(n))})')Kommunikasjon om D&C i jobbintervju
Når De presenterer en D&C-løsning i et intervju: (1) Angi de tre trinnene tydelig: "Jeg vil dele ved midtpunktet, løse hver halvdel rekursivt og deretter kombinere ved å flette dem sammen." (2) Identifiser basistilfellet tydelig. (3) Utled rekurrensen: T(n) = 2T(n/2) + O(n). (4) Bruk Master Theorem eller et rekursjonstre til å utlede O(n log n). (5) Nevn når D&C er bedre eller dårligere enn alternativene (DP for overlappende delproblemer, Kadane's for maksimalt delarray).
# D&C interview template to memorize:
def dc_template(problem, lo, hi):
# 1. BASE CASE (state it first)
if lo == hi: return solve_base(problem, lo)
# 2. DIVIDE
mid = (lo + hi) // 2
# 3. CONQUER
left = dc_template(problem, lo, mid)
right = dc_template(problem, mid + 1, hi)
# 4. COMBINE (this is where the algorithm-specific logic goes)
return combine_results(left, right, problem, lo, mid, hi)
def solve_base(p, i): return p[i]
def combine_results(l, r, p, lo, mid, hi): return max(l, r)
print('D&C template: base-divide-conquer-combine')
print('Complexity usually: T(n)=2T(n/2)+O(n) → O(n log n)')Kort kontroll
Test forståelsen av konseptene innen Data Structures & Algorithms — Coding Interview Prep fra denne leksjonen.
Oppsummering av leksjonen
I denne leksjonen lærte De: Divide and Conquer følger malen: basistilfelle → del ved midtpunktet → løs rekursivt → kombiner, T(n) = 2T(n/2) + O(n) gir O(n log n) ved hjelp av Master Theorem, tilfelle 2, og D&C er optimalt for uavhengige delproblemer, mens DP trengs når delproblemene overlapper. Deretter bruker vi D&C til å telle inversjoner i et array ved hjelp av en modifisert merge sort.
Lær deg Python med en AI-veileder – gratis
Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.
- Kurs
- 30
- Leksjoner
- 120
Ofte stilte spørsmål
Er leksjonen «Mal for splitt og hersk» gratis?
Ja – du kan lese valgfritt 3 av leksjonene i læringsstien DSA Interview Prep, inkludert «Mal for splitt og hersk», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i DSA Interview Prep inneholder totalt 4 leksjoner.
Hva lærer jeg i «Mal for splitt og hersk»?
Trekk ut malen i tre trinn (splitt, løs, kombiner) fra flettesortering, og bruk den systematisk på nye problemformer. Du øver på DSA Interview Prep med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.
Trenger jeg erfaring for å begynne med DSA Interview Prep?
Ingen tidligere erfaring er nødvendig. DSA Interview Prep på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 1 av 4.
Hvor lang tid tar leksjonen «Mal for splitt og hersk»?
De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.
Kan jeg skrive og kjøre kode i denne DSA Interview Prep-leksjonen?
Ja. Alle DSA Interview Prep-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.
Alle leksjonene i dette kurset
- Mal for splitt og hersk
- Tell inversjoner med modifisert flettesortering
- Majoritetselement: Boyer-Moore-avstemning
- Medianen av to sorterte tabeller