DSA Interview Prep · leksjon

Intervallplanlegging og sammenslåing

Løs problemene «meeting-rooms» og «non-overlapping-intervals» ved å sortere etter sluttid, og «merge-intervals» ved å sortere etter starttid.

Leksjon 2 av 413 trinn

Intervallplanlegging og sammenslåing er en gratis leksjon i DSA Interview Prep på CoddyKit. Dette er leksjon 2 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.

Oversikt over intervallproblemer

Intervallproblemer dukker stadig opp i intervjuer om planlegging, kalenderstyring og ressursallokering. De viktigste mønstrene er: slå sammen overlappende intervaller, telle minimum antall møterom, finne den største mengden ikke-overlappende intervaller og sette inn et nytt intervall. De fleste intervallproblemer begynner med samme trinn: sorter intervallene etter starttidspunkt (eller sluttidspunkt, avhengig av problemet). Å velge riktig sorteringsnøkkel er ofte den vanskeligste delen.

# Intervals: each = [start, end] (inclusive or exclusive by problem)
# Example:
intervals = [[1,3],[2,6],[8,10],[15,18]]
# Sorted by start (already sorted here)
# Visually:
# [1,3]    |-|
# [2,6]      |---|
# [8,10]             |--|
# [15,18]                    |---|
print('Intervals ready for analysis')

Slå sammen overlappende intervaller

Slå sammen intervaller (LeetCode 56): gitt en liste med intervaller skal alle overlappende intervaller slås sammen. Algoritme: sorter etter starttidspunkt. Gå gjennom den sorterte listen; hvis det gjeldende intervallet overlapper med det sist sammenslåtte intervallet (starten er ≤ den sist sammenslåtte slutten), utvid slutten på det sist sammenslåtte intervallet til maksimum av de to sluttene. Ellers legges det gjeldende intervallet til som et nytt sammenslått intervall. Tid: O(n log n) for sorteringen, O(n) for sammenslåingen.

def merge_intervals(intervals):
    intervals.sort(key=lambda x: x[0])  # sort by start
    merged = [intervals[0]]
    for start, end in intervals[1:]:
        last_end = merged[-1][1]
        if start <= last_end:
            # Overlapping: extend the last interval
            merged[-1][1] = max(last_end, end)
        else:
            # Non-overlapping: add as new interval
            merged.append([start, end])
    return merged

print(merge_intervals([[1,3],[2,6],[8,10],[15,18]]))
# [[1,6],[8,10],[15,18]]
print(merge_intervals([[1,4],[4,5]]))
# [[1,5]] (touching intervals merge)

Sett inn intervall

Sett inn intervall (LeetCode 57): gitt en sortert liste uten overlapp skal et nytt intervall settes inn, og intervallene skal slås sammen på nytt. Gå gjennom listen i tre faser: (1) Legg til alle intervaller som slutter før det nye intervallet begynner. (2) Slå sammen alle intervaller som overlapper med det nye intervallet (utvid grensene). (3) Legg til alle gjenværende intervaller. Dette er én gjennomgang i O(n) etter sorteringen i O(n log n) (som allerede er utført i denne oppgaven).

def insert_interval(intervals, new_interval):
    result = []
    i = 0
    n = len(intervals)
    # Phase 1: intervals before new_interval
    while i < n and intervals[i][1] < new_interval[0]:
        result.append(intervals[i])
        i += 1
    # Phase 2: merge overlapping intervals
    while i < n and intervals[i][0] <= new_interval[1]:
        new_interval[0] = min(new_interval[0], intervals[i][0])
        new_interval[1] = max(new_interval[1], intervals[i][1])
        i += 1
    result.append(new_interval)
    # Phase 3: remaining intervals
    while i < n:
        result.append(intervals[i])
        i += 1
    return result

print(insert_interval([[1,3],[6,9]], [2,5]))  # [[1,5],[6,9]]
print(insert_interval([[1,2],[3,5],[6,7],[8,10],[12,16]], [4,8]))
# [[1,2],[3,10],[12,16]]

Møterom I: Er det mulig å delta på alle møtene?

Møterom I (LeetCode 252): gitt tidsintervaller for møter skal det avgjøres om en person kan delta på alle møtene. Sorter etter starttidspunkt; hvis et møte begynner før det forrige møtet slutter, overlapper de. Dette er den enkleste intervallsjekken – totalt O(n log n). Hovedinnsikten er at det etter sorteringen bare er nødvendig å sammenligne påfølgende par.

def can_attend_meetings(intervals):
    intervals.sort(key=lambda x: x[0])
    for i in range(1, len(intervals)):
        # Current meeting starts before previous ends?
        if intervals[i][0] < intervals[i-1][1]:
            return False
    return True

print(can_attend_meetings([[0,30],[5,10],[15,20]]))  # False (0,30 overlaps 5,10)
print(can_attend_meetings([[7,10],[2,4]]))           # True (4 < 7, no overlap)

Møterom II: Minimum antall rom

Møterom II (LeetCode 253): finn minimum antall konferanserom som trengs for å holde alle møtene samtidig. Bruk en min-heap for å holde oversikt over rommet som blir ledig først. Sorter møtene etter starttidspunkt. For hvert nye møte: hvis det begynner etter sluttiden til rommet som blir ledig først, brukes rommet på nytt (ta det ut og legg det inn igjen). Ellers åpnes et nytt rom. Størrelsen på heapen til slutt er lik antallet rom som trengs.

import heapq

def min_meeting_rooms(intervals):
    if not intervals: return 0
    intervals.sort(key=lambda x: x[0])  # sort by start
    heap = []  # min-heap of end times
    for start, end in intervals:
        if heap and heap[0] <= start:
            heapq.heapreplace(heap, end)  # reuse earliest-ending room
        else:
            heapq.heappush(heap, end)     # open a new room
    return len(heap)

print(min_meeting_rooms([[0,30],[5,10],[15,20]]))  # 2
print(min_meeting_rooms([[7,10],[2,4]]))           # 1
print(min_meeting_rooms([[9,10],[4,9],[4,17]]))    # 2

Alternativ med sveipelinje for telling av rom

En alternativ metode i O(n log n) er sveipelinje. Opprett hendelser for starten (+1) og slutten (-1) av hvert intervall. Sorter alle hendelsene etter tidspunkt (ved lik tid: slutt før start dersom endepunktene ikke skal inkluderes). Sveip fra venstre mot høyre og hold oversikt over antallet aktive møter. Det høyeste antallet er minimum antall rom som trengs. Metoden er mer intuitiv for noen og kan generaliseres til andre telleproblemer med intervaller.

def min_rooms_sweep(intervals):
    events = []
    for start, end in intervals:
        events.append((start, 1))   # meeting starts
        events.append((end, -1))    # meeting ends
    # Sort: same time → end (-1) before start (1) if exclusive
    events.sort(key=lambda x: (x[0], x[1]))
    max_rooms = current = 0
    for _, delta in events:
        current += delta
        max_rooms = max(max_rooms, current)
    return max_rooms

print(min_rooms_sweep([[0,30],[5,10],[15,20]]))  # 2
print(min_rooms_sweep([[1,5],[2,6],[3,7]]))       # 3 (all overlap at t=3)

Ikke-overlappende intervaller: Maksimalt utvalg

Ikke-overlappende intervaller (LeetCode 435): finn minimum antall intervaller som må fjernes for at de gjenværende ikke skal overlappe. Dette tilsvarer å finne maksimalt antall ikke-overlappende intervaller (aktivitetsutvalg) og returnere resten som intervaller som skal fjernes. Sorter etter sluttidspunkt: behold grådig intervallet som slutter tidligst (slik maksimeres plassen for fremtidige intervaller). Når det neste intervallet overlapper, forkastes det (og antallet fjerninger økes).

def erase_overlap_intervals(intervals):
    if not intervals: return 0
    intervals.sort(key=lambda x: x[1])  # sort by END time
    removals = 0
    last_end = float('-inf')
    for start, end in intervals:
        if start >= last_end:
            last_end = end  # keep this interval
        else:
            removals += 1   # remove this interval (it overlaps)
    return removals

print(erase_overlap_intervals([[1,2],[2,3],[3,4],[1,3]]))  # 1 (remove [1,3])
print(erase_overlap_intervals([[1,2],[1,2],[1,2]]))        # 2
print(erase_overlap_intervals([[1,2],[2,3]]))              # 0 (no overlap)

Hvorfor sortere etter sluttid, ikke starttid?

For aktivitetsutvelgelse (størst mulig mengde aktiviteter uten overlapp) er det bevist at det er optimalt å sortere etter sluttid. Intuisjonen er at en aktivitet som slutter tidlig, gir mer plass til fremtidige aktiviteter. Hvis vi sorterer etter starttid, kan vi velge en svært lang aktivitet som starter tidlig, og dermed blokkere mange kortere aktiviteter som kommer senere. Bytteargument: Hvis den optimale løsningen velger aktivitet A i stedet for den som slutter først, G, kan A byttes ut med G — G slutter ikke senere, så den kolliderer ikke med noe A ikke kolliderte med.

# Counterexample for sorting by START time:
# [[1,10],[2,3],[4,5]] — sorted by start: [1,10],[2,3],[4,5]
# Sort-by-start greedy keeps [1,10], can't add [2,3] or [4,5] (all overlap [1,10])
# Selects: 1 interval

# Sort-by-end greedy:
# [[2,3],[4,5],[1,10]] — sorted by end
# Keep [2,3] (end=3), then [4,5] (start=4 >= 3, keep), then [1,10] (start=1 < 5, skip)
# Selects: 2 intervals — OPTIMAL

intervals = [[1,10],[2,3],[4,5]]
intervals.sort(key=lambda x: x[1])
last_end = float('-inf')
count = 0
for s, e in intervals:
    if s >= last_end:
        count += 1; last_end = e
print('Max non-overlapping:', count)  # 2

Skjæringspunkter mellom intervallister

Skjæringspunkter mellom intervallister (LeetCode 986): finn alle par som overlapper, fra to sorterte intervallister. Bruk en topeker-tilnærming. Beregn skjæringspunktet for det gjeldende paret i hvert trinn (maksimum av starttidene, minimum av sluttidene). Hvis start ≤ slutt, er skjæringspunktet gyldig. Flytt deretter pekeren for intervallet som slutter først. Tidskompleksitet O(m+n).

def interval_intersection(A, B):
    result = []
    i = j = 0
    while i < len(A) and j < len(B):
        # Intersection boundaries
        lo = max(A[i][0], B[j][0])
        hi = min(A[i][1], B[j][1])
        if lo <= hi:
            result.append([lo, hi])  # valid intersection
        # Advance pointer of interval that ends first
        if A[i][1] < B[j][1]:
            i += 1
        else:
            j += 1
    return result

A = [[0,2],[5,10],[13,23],[24,25]]
B = [[1,5],[8,12],[15,24],[25,26]]
print(interval_intersection(A, B))
# [[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]]

Partisjonering av etiketter

Partisjonering av etiketter (LeetCode 763): del en streng opp i så mange deler som mulig, slik at hvert tegn forekommer i høyst én del. Grådig strategi: Finn den siste forekomsten av hvert tegn. Gå gjennom strengen og oppretthold en max_end. Når i == max_end, er den gjeldende partisjonen ferdig — registrer lengden og start en ny partisjon. Dette er egentlig et problem med sammenslåing av intervaller.

def partition_labels(s):
    last = {c: i for i, c in enumerate(s)}  # last occurrence of each char
    partitions = []
    start = max_end = 0
    for i, c in enumerate(s):
        max_end = max(max_end, last[c])
        if i == max_end:  # partition complete
            partitions.append(max_end - start + 1)
            start = i + 1
    return partitions

print(partition_labels('ababcbacadefegdehijhklij'))
# [9, 7, 8] — parts 'ababcbaca', 'defegde', 'hijhklij'

Oppsummering av intervallproblemer

Behersk disse fire mønstrene for intervaller: (1) Slå sammen: sorter etter starttid og utvid det siste intervallet ved overlapp. (2) Tell rom: sorter etter starttid og bruk en min-heap med sluttider. (3) Maksimalt antall intervaller uten overlapp: sorter etter sluttid og velg grådig. (4) Sett inn: lineær gjennomgang i tre faser. Sorteringsnøkkelen er viktig: sammenslåing bruker starttid, mens maksimering av utvalget bruker sluttid. Tidskompleksiteten er alltid O(n log n), dominert av sorteringen; sammenslåing og gjennomgang er O(n).

# Quick reference:
# Merge intervals:         sort by start, extend if overlap
# Insert interval:         three-phase linear scan
# Meeting rooms (can?):   sort by start, check consecutive overlap
# Meeting rooms (min?):   sort by start, min-heap of end times / sweep
# Max non-overlapping:    sort by END, greedy keep
# Min removals:           n - max_non_overlapping
# Interval intersection:  two pointers on sorted lists

print('Pattern: sort key is the decisive choice')
print('Merge → sort by start')
print('Activity selection → sort by end')
print('Room count → sort by start + heap of ends')

Hurtigsjekk

Test forståelsen av konseptene fra Data Structures & Algorithms — Coding Interview Prep i denne leksjonen.

Oppsummering av leksjonen

I denne leksjonen har De lært: å slå sammen intervaller ved å sortere etter starttid og utvide det siste intervallet når det oppstår overlapp, at minimum antall møterom bruker sortering etter starttid sammen med en min-heap av sluttider, og gjenbruker rom når rommet som blir ledig først, er tilgjengelig, samt at maksimalt antall intervaller uten overlapp bruker grådig utvelgelse etter sluttid. Deretter tar vi for oss Jump Game I og II — problemer med nåbarhet og minimalt antall hopp som løses ved grådig utvidelse av rekkevidden.

Gratis å komme i gang

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 «Intervallplanlegging og sammenslåing» gratis?

Ja – du kan lese valgfritt 3 av leksjonene i læringsstien DSA Interview Prep, inkludert «Intervallplanlegging og sammenslåing», 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 «Intervallplanlegging og sammenslåing»?

Løs problemene «meeting-rooms» og «non-overlapping-intervals» ved å sortere etter sluttid, og «merge-intervals» ved å sortere etter starttid. 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 2 av 4.

Hvor lang tid tar leksjonen «Intervallplanlegging og sammenslåing»?

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

  1. Grådig algoritme eller DP: Når skal du bruke hva
  2. Intervallplanlegging og sammenslåing
  3. Jump Game I og II
  4. Task Scheduler og Gas Station
← Tilbake til DSA Interview Prep