Intervallschemaläggning och sammanslagning
Lös meeting-rooms och non-overlapping-intervals genom att sortera efter sluttid, och merge-intervals genom att sortera efter starttid.
Intervallschemaläggning och sammanslagning är en gratis lektion i Förberedelse inför kodningsintervjuer på CoddyKit. Detta är lektion 2 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.
Översikt över intervallproblem
Intervallproblem dyker ständigt upp i intervjuer om schemaläggning, kalenderhantering och resursallokering. De viktigaste mönstren är: slå ihop överlappande intervall, räkna minsta antal mötesrum, hitta största mängd icke-överlappande intervall och lägga in ett nytt intervall. De flesta intervallproblem börjar med samma steg: sortera intervallen efter starttid (eller sluttid, beroende på problemet). Att välja rätt sorteringsnyckel är ofta den svåraste 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å ihop överlappande intervall
Merge Intervals (LeetCode 56): givet en lista med intervall ska alla överlappande intervall slås ihop. Algoritm: sortera efter starttid. Gå igenom den sorterade listan; om det aktuella intervallet överlappar det senast sammanslagna intervallet (dess start ≤ slutet för det senast sammanslagna intervallet), utökar ni det senast sammanslagna intervallets slut till det största av de två sluten. Annars lägger ni till det aktuella intervallet som ett nytt sammanslaget intervall. Tid: O(n log n) för sorteringen och O(n) för sammanslagningen.
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)Lägg in intervall
Insert Interval (LeetCode 57): givet en sorterad lista utan överlappningar ska ett nytt intervall läggas in och intervallen slås ihop igen. Gå igenom listan i tre faser: (1) Lägg till alla intervall som slutar innan det nya intervallet börjar. (2) Slå ihop alla intervall som överlappar det nya intervallet (utvidga dess gränser). (3) Lägg till alla återstående intervall. Detta är ett enda genomlopp i O(n) efter sorteringen i O(n log n) (som redan är gjord i det här problemet).
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ötesrum I: Kan alla möten besökas
Meeting Rooms I (LeetCode 252): givet intervall för mötestider ska ni avgöra om en person kan delta i alla möten. Sortera efter starttid; om något möte börjar innan det föregående slutar överlappar mötena. Detta är den enklaste intervallkontrollen – totalt O(n log n). Den viktiga insikten är att ni efter sorteringen bara behöver jämföra intilliggande 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ötesrum II: Minsta antal rum
Meeting Rooms II (LeetCode 253): hitta det minsta antalet konferensrum som krävs för att hålla alla möten samtidigt. Använd en min-heap för att hålla reda på rummet som slutar tidigast. Sortera mötena efter starttid. För varje nytt möte: om det börjar efter sluttiden för rummet som slutar tidigast återanvänder ni det rummet (ta bort och lägg till igen). Annars öppnar ni ett nytt rum. Heapens storlek i slutet är lika med antalet rum som behövs.
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]])) # 2Alternativ med sveplinje för rumsräkning
Ett alternativ i O(n log n): sveplinje. Skapa händelser för varje intervalls start (+1) och slut (-1). Sortera alla händelser efter tid (vid lika tider: slut före start om ni vill ha icke-inkluderande intervall). Svep från vänster till höger och håll reda på ett löpande antal aktiva möten. Det största antalet är det minsta antalet rum som behövs. Detta är mer intuitivt för vissa och kan generaliseras till andra räkneproblem för intervall.
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)Icke-överlappande intervall: maximalt urval
Non-Overlapping Intervals (LeetCode 435): hitta det minsta antalet intervall som måste tas bort för att de återstående inte ska överlappa. Detta motsvarar att hitta det största antalet icke-överlappande intervall (aktivitetsurval) och returnera de återstående som borttagna. Sortera efter sluttid: behåll med greedy-strategin det intervall som slutar tidigast (det ger mest utrymme för framtida intervall). När nästa intervall överlappar förkastar ni det (räkna en borttagning).
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)Varför sortera efter sluttid, inte starttid?
För aktivitetsurval (största möjliga mängd aktiviteter utan överlappning) är det bevisat optimalt att sortera efter sluttid. Intuitionen är att en aktivitet som slutar tidigt lämnar mer utrymme för framtida aktiviteter. Om vi sorterar efter starttid kan vi välja en mycket lång aktivitet som börjar tidigt och blockerar många kortare aktiviteter som börjar senare. Bytesargument: om den optimala lösningen väljer aktivitet A framför den aktivitet G som slutar tidigast, byt ut A mot G — G slutar inte senare och står därför inte i konflikt med något som A inte stod i konflikt 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) # 2Skärningar mellan intervallistor
Skärningar mellan intervallistor (LeetCode 986): hitta alla par som skär varandra från två sorterade intervallistor. Använd en tvåpekaralgoritm. Beräkna skärningen mellan det aktuella paret i varje steg (det största av startpunkterna och det minsta av slutpunkterna). Om start ≤ slut är skärningen giltig. Flytta sedan pekaren för det intervall som slutar först. Tidskomplexiteten är 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]]Partitionering av tecken
Partitionering av tecken (LeetCode 763): dela upp en sträng i så många delar som möjligt, så att varje tecken förekommer i högst en del. Girig metod: hitta den sista förekomsten av varje tecken. Gå igenom strängen och håll reda på ett max_end. När i == max_end är den aktuella partitionen klar — registrera dess längd och börja på en ny partition. Detta är i själva verket ett intervallsammanslagningsproblem.
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'Sammanfattning av intervallproblem
Behärska dessa fyra mönster för intervall: (1) Sammanfoga: sortera efter start och förläng det sista intervallet om det överlappar. (2) Räkna rum: sortera efter start och använd en min-heap med sluttider. (3) Maximalt antal utan överlappning: sortera efter slut och välj girigt. (4) Infoga: en linjär genomsökning i tre faser. Sorteringsnyckeln är viktig: sammanfogning använder start, medan maximering använder slut. Tidskomplexiteten är alltid O(n log n), där sorteringen dominerar; sammanfogning och genomsökning är 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')Snabbtest
Testa era kunskaper om begreppen inom Data Structures & Algorithms — Coding Interview Prep från den här lektionen.
Sammanfattning av lektionen
I den här lektionen har ni lärt er: slå ihop intervall genom att sortera efter start och förlänga det sista intervallet om en överlappning uppstår, minsta antal mötesrum kräver sortering efter start plus en min-heap med sluttider, där rum återanvänds när rummet som slutar tidigast blir ledigt, samt maximalt antal intervall utan överlappning använder girigt urval efter sluttid. Nästa steg är Jump Game I och II — problem om nåbarhet och minsta antal hopp som löses genom girig räckviddsutvidgning.
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 ”Intervallschemaläggning och sammanslagning” gratis?
Ja – hela texten till ”Intervallschemaläggning och sammanslagning” 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 ”Intervallschemaläggning och sammanslagning”?
Lös meeting-rooms och non-overlapping-intervals genom att sortera efter sluttid, och merge-intervals genom att sortera efter starttid. 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 2 av 4.
Hur lång tid tar lektionen ”Intervallschemaläggning och sammanslagning”?
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
- Giriga algoritmer eller DP: när används vad
- Intervallschemaläggning och sammanslagning
- Jump Game I och II
- Task Scheduler och Gas Station