0Pricing
DSA Interview Prep · Pelajaran

Penjadwalan dan Penggabungan Interval

Selesaikan masalah ruang rapat dan interval yang tidak tumpang tindih dengan mengurutkan berdasarkan waktu selesai, lalu gabungkan interval dengan mengurutkan berdasarkan waktu mulai

Penjadwalan dan Penggabungan Interval adalah pelajaran DSA Interview Prep gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar DSA Interview Prep, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus DSA Interview Prep mencakup 4 pelajaran total.

Ikhtisar Masalah Interval

Masalah interval sering muncul dalam wawancara tentang penjadwalan, pengelolaan kalender, dan alokasi sumber daya. Pola utamanya adalah: gabungkan interval yang saling tumpang tindih, hitung jumlah minimum ruang rapat, temukan himpunan maksimum interval yang tidak saling tumpang tindih, dan insert interval baru. Sebagian besar masalah interval dimulai dengan langkah yang sama: sort interval berdasarkan waktu mulai (atau waktu end, bergantung pada masalahnya). Menentukan kunci pengurutan yang tepat sering kali menjadi bagian tersulit.

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

Gabungkan Interval yang Saling Tumpang Tindih

Gabungkan Interval (LeetCode 56): diberikan daftar interval, gabungkan semua interval yang saling tumpang tindih. Algoritma: sort berdasarkan waktu mulai. Telusuri daftar yang telah diurutkan; jika interval saat ini tumpang tindih dengan interval gabungan terakhir (mulainya ≤ end gabungan terakhir), perluas end interval gabungan terakhir hingga nilai maksimum dari kedua end. Jika tidak, append interval saat ini sebagai interval gabungan baru. Waktu: O(n log n) untuk pengurutan, O(n) untuk penggabungan.

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)

Sisipkan Interval

Sisipkan Interval (LeetCode 57): diberikan daftar yang telah diurutkan dan tidak saling tumpang tindih, sisipkan interval baru lalu gabungkan kembali. Telusuri dalam tiga tahap: (1) Tambahkan semua interval yang berakhir sebelum interval baru dimulai. (2) Gabungkan semua interval yang tumpang tindih dengan interval baru (perluas batas-batasnya). (3) Tambahkan semua interval yang tersisa. Ini merupakan satu kali lintasan O(n) setelah pengurutan O(n log n) (yang sudah dilakukan dalam masalah ini).

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

Ruang Rapat I: Dapat Menghadiri Semua?

Ruang Rapat I (LeetCode 252): diberikan interval waktu rapat, tentukan apakah seseorang dapat menghadiri semua rapat. Sort berdasarkan waktu mulai; jika ada rapat yang dimulai sebelum rapat sebelumnya berakhir, keduanya saling tumpang tindih. Ini adalah pemeriksaan interval paling sederhana — total O(n log n). Inti pentingnya: setelah pengurutan, Anda hanya perlu membandingkan pasangan yang berurutan.

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)

Ruang Rapat II: Ruangan Minimum

Ruang Rapat II (LeetCode 253): temukan jumlah minimum ruang konferensi yang diperlukan untuk menyelenggarakan semua rapat secara bersamaan. Gunakan tumpukan minimum untuk melacak ruangan yang memiliki waktu selesai paling awal. Sort rapat berdasarkan waktu mulai. Untuk setiap rapat baru: jika rapat tersebut dimulai setelah waktu end ruangan yang selesai paling awal, gunakan kembali ruangan itu (pop lalu masukkan kembali). Jika tidak, buka ruangan baru. Ukuran tumpukan pada akhir proses sama dengan jumlah ruangan yang diperlukan.

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

Alternatif Garis Sapuan untuk Menghitung Ruangan

Pendekatan O(n log n) alternatif: garis sapuan. Buat peristiwa untuk setiap awal interval (+1) dan end (-1). Urutkan semua peristiwa berdasarkan time (jika waktunya sama: letakkan end sebelum awal jika Anda menginginkan batas yang tidak inklusif). Sapukan dari kiri ke kanan sambil mempertahankan jumlah rapat aktif. Jumlah maksimum tersebut adalah jumlah minimum ruangan yang diperlukan. Pendekatan ini lebih intuitif bagi sebagian orang dan dapat digeneralisasi ke masalah penghitungan lain pada interval.

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)

Interval Tanpa Tumpang Tindih: Pemilihan Maksimum

Interval Tanpa Tumpang Tindih (LeetCode 435): temukan jumlah minimum interval yang harus dihapus agar interval yang tersisa tidak saling tumpang tindih. Ini setara dengan menemukan jumlah maksimum interval yang tidak saling tumpang tindih (pemilihan aktivitas), lalu mengembalikan sisanya sebagai interval yang dihapus. Urutkan berdasarkan waktu selesai: secara serakah pertahankan interval yang selesai paling awal (memaksimalkan ruang untuk interval berikutnya). Ketika interval berikutnya tumpang tindih, discard interval tersebut (hitung satu penghapusan).

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)

Mengapa Mengurutkan Berdasarkan Waktu Selesai, Bukan Waktu Mulai?

Untuk pemilihan aktivitas (himpunan maksimum tanpa tumpang tindih), pengurutan berdasarkan waktu selesai terbukti optimal. Intuisinya: aktivitas yang selesai lebih awal menyisakan lebih banyak ruang untuk aktivitas berikutnya. Jika kita mengurutkan berdasarkan waktu mulai, kita mungkin memilih aktivitas yang dimulai lebih awal tetapi sangat panjang, sehingga menghalangi banyak aktivitas berikutnya yang lebih singkat. Argumen pertukaran: jika solusi optimal memilih aktivitas A alih-alih G yang selesai paling awal, tukar A dengan G — G tidak selesai lebih lambat, jadi G tidak berkonflik dengan aktivitas apa pun yang tidak berkonflik dengan A.

# 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

Irisan Daftar Interval

Irisan Daftar Interval (LeetCode 986): temukan semua pasangan yang beririsan dari dua daftar interval terurut. Gunakan pendekatan dua penunjuk. Pada setiap langkah, hitung irisan pasangan saat ini (nilai maksimum dari titik mulai, nilai minimum dari titik selesai). Jika mulai ≤ selesai, irisan tersebut valid. Kemudian majukan penunjuk interval yang berakhir lebih dulu. Waktu 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]]

Partisi Label

Partisi Label (LeetCode 763): partisi teks menjadi sebanyak mungkin bagian sehingga setiap karakter muncul paling banyak dalam satu bagian. Serakah: untuk setiap karakter, temukan kemunculan terakhirnya. Telusuri teks sambil mempertahankan max_end. Saat i == max_end, partisi saat ini selesai — catat panjangnya dan mulai partisi baru. Ini adalah masalah penggabungan interval yang terselubung.

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'

Ringkasan Masalah Interval

Kuasai empat pola interval ini: (1) Penggabungan: urutkan berdasarkan waktu mulai, perluas interval terakhir jika terjadi tumpang tindih. (2) Menghitung ruangan: urutkan berdasarkan waktu mulai, gunakan tumpukan minimum berisi waktu selesai. (3) Maksimum tanpa tumpang tindih: urutkan berdasarkan waktu selesai, pilih secara serakah. (4) Penyisipan: pemindaian linear tiga tahap. Kunci pengurutan penting: penggabungan menggunakan waktu mulai, pemilihan maksimum menggunakan waktu selesai. Kompleksitas waktu selalu O(n log n), didominasi oleh pengurutan; penggabungan/pemindaian adalah 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')

Pemeriksaan Singkat

Uji pemahaman Anda tentang konsep Struktur Data & Algoritma — Persiapan Wawancara Pemrograman dari pelajaran ini.

Rangkuman Pelajaran

Dalam pelajaran ini Anda mempelajari: menggabungkan interval dengan mengurutkannya berdasarkan waktu mulai dan memperluas interval terakhir jika terjadi tumpang tindih, jumlah minimum ruangan rapat menggunakan pengurutan berdasarkan waktu mulai dan tumpukan minimum berisi waktu selesai, dengan menggunakan kembali ruangan saat ruangan yang selesai paling awal sudah tersedia, dan interval maksimum tanpa tumpang tindih menggunakan pemilihan serakah berdasarkan waktu selesai. Berikutnya kita akan membahas Permainan Lompatan I dan II — masalah keterjangkauan dan jumlah lompatan minimum yang diselesaikan dengan perluasan jangkauan secara serakah.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Penjadwalan dan Penggabungan Interval” gratis?

Ya — teks lengkap “Penjadwalan dan Penggabungan Interval” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus DSA Interview Prep, upgrade ke CoddyKit PRO. Kursus DSA Interview Prep mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Penjadwalan dan Penggabungan Interval”?

Selesaikan masalah ruang rapat dan interval yang tidak tumpang tindih dengan mengurutkan berdasarkan waktu selesai, lalu gabungkan interval dengan mengurutkan berdasarkan waktu mulai Kamu berlatih DSA Interview Prep dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai DSA Interview Prep?

Tidak diperlukan pengalaman sebelumnya. DSA Interview Prep di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.

Berapa lama pelajaran “Penjadwalan dan Penggabungan Interval” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran DSA Interview Prep ini?

Ya. Setiap pelajaran DSA Interview Prep menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Greedy vs DP: Kapan Menggunakan Masing-Masing
  2. Penjadwalan dan Penggabungan Interval
  3. Jump Game I dan II
  4. Penjadwal Tugas dan Pompa Bensin
← Kembali ke DSA Interview Prep