Persediaan Temu Duga Pengaturcaraan · Pelajaran

Penjadual Tugas dan Stesen Minyak

Gunakan penaakulan tamak untuk masalah tempoh penyejukan penjadual tugas CPU dan masalah kebolehlaksanaan stesen minyak berbentuk bulatan.

Pelajaran 4 daripada 413 langkah

Penjadual Tugas dan Stesen Minyak ialah pelajaran Persediaan Temu Duga Pengaturcaraan percuma di CoddyKit. Ini ialah pelajaran 4 daripada 4. Anda boleh membaca keseluruhan pelajaran di bawah secara percuma — kemudian berlatih secara praktikal dalam pelayar menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Persediaan Temu Duga Pengaturcaraan, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Persediaan Temu Duga Pengaturcaraan merangkumi sejumlah 4 pelajaran.

Masalah Penjadual Tugasan

Penjadual Tugasan (LeetCode 621): diberikan senarai tugasan CPU (setiap satu dilabel A-Z) dan tempoh penyejukan n, cari bilangan selang CPU minimum untuk menyiapkan semua tugasan. Tugasan yang sama mesti menunggu sekurang-kurangnya n selang sebelum dijalankan semula. Selang melahu dibenarkan. Bagi tugasan ['A','A','A','B','B','B'] dengan tempoh penyejukan 2, jawapannya ialah 8: A→B→idle→A→B→idle→A→B.

# Task Scheduler example
tasks = ['A','A','A','B','B','B']
n = 2  # cooldown
# One optimal schedule: A B _ A B _ A B
# Intervals: 1 2 3 4 5 6 7 8 → answer = 8

# Another example: tasks=['A','A','A','B','B','C'] n=2
# A B C A B _ A → 7 intervals
print('Understanding the cooldown constraint')
print('Same task needs n intervals gap between runs')

Formula Tamak untuk Penjadual Tugasan

Pemerhatian utama: jumlah masa ditentukan oleh tugasan yang paling kerap. Jika tugasan yang paling kerap muncul f kali dengan kiraan max_count (bilangan tugasan yang mempunyai kekerapan f), masanya ialah max(len(tasks), (f-1) * (n+1) + max_count). Formulanya: bina f-1 bingkai berukuran n+1, isikannya dengan tugasan lain, dan add kitaran terakhir. Jika tugasan lain mengisi semua ruang melahu (banyak tugasan yang pelbagai), jalankan sahaja semua tugasan tanpa masa melahu.

from collections import Counter

def least_interval(tasks, n):
    count = Counter(tasks)
    max_freq = max(count.values())
    # How many tasks have the maximum frequency?
    max_count = sum(1 for c in count.values() if c == max_freq)
    # Formula: max of total tasks (no idle) or frame-based calculation
    frame_time = (max_freq - 1) * (n + 1) + max_count
    return max(len(tasks), frame_time)

print(least_interval(['A','A','A','B','B','B'], 2))  # 8
print(least_interval(['A','A','A','B','B','B'], 0))  # 6 (no cooldown)
print(least_interval(['A','A','A','A','B','C'], 3))  # 10

Mengapa Formula Ini Berfungsi

Bayangkan jadual sebagai grid dengan n+1 lajur (satu ruang tugasan + n ruang penyejukan). Tugasan A yang paling kerap muncul (kekerapan f) memerlukan f baris. Antara kemunculan pertama dan terakhir, terdapat f-1 bingkai penuh dengan n+1 ruang. Selain itu, terdapat bingkai separa terakhir yang mengandungi semua tugasan dengan kekerapan maksimum. Jika terdapat tugasan yang pelbagai dalam jumlah mencukupi, tugasan tersebut mengisi semua ruang melahu, dan kiraan tugasan sebenar melebihi masa bingkai — ambil nilai yang lebih besar antara kedua-duanya.

# Visualise frame structure for AAABBB, n=2
# Frame size = n+1 = 3
# f = 3 (A appears 3 times), max_count = 2 (A and B both appear 3 times)
# Grid:
# [A B _]  ← frame 1
# [A B _]  ← frame 2  
# [A B  ]  ← last partial frame (max_count=2 cells)
# Total = (3-1)*3 + 2 = 6 + 2 = 8

# If tasks = AAAABBCC, n=2: max_freq=4 (A), max_count=1
# (4-1)*(2+1)+1 = 9+1 = 10
# But len(tasks)=8 < 10, so answer is 10
tasks2 = ['A','A','A','A','B','B','C','C']
from collections import Counter
count = Counter(tasks2)
mf = max(count.values())
mc = sum(1 for c in count.values() if c == mf)
print(f'Frame formula: ({mf}-1)*{2+1}+{mc} = {(mf-1)*(2+1)+mc}')
print(f'Max(len={len(tasks2)}, frame={max(len(tasks2),(mf-1)*3+mc)}) = {max(len(tasks2),(mf-1)*3+mc)}')

Alternatif Simulasi Timbunan

Simulasi berasaskan timbunan menghasilkan jadual sebenar (bukan sekadar kiraan). Pada setiap langkah, ambil tugasan tersedia yang paling kerap muncul (timbunan maksimum). Selepas melaksanakannya, gunakan tempoh penyejukan: jangan masukkannya semula sehingga n langkah kemudian. Gunakan baris gilir untuk menjejak tugasan yang sedang menyejuk. Ini berjalan dalam O(total_time × log k), dengan k ialah bilangan tugasan berbeza. Walaupun betul, formula lebih pantas. Ketahui kedua-duanya — penemuduga mungkin meminta jadual itu sendiri.

import heapq
from collections import deque, Counter

def task_scheduler_simulate(tasks, n):
    count = Counter(tasks)
    heap = [-c for c in count.values()]  # max-heap using negation
    heapq.heapify(heap)
    time = 0
    cooldown = deque()  # (available_at, neg_count)
    while heap or cooldown:
        time += 1
        if heap:
            c = heapq.heappop(heap) + 1  # use one instance
            if c < 0:  # still has remaining tasks
                cooldown.append((time + n, c))
        if cooldown and cooldown[0][0] == time:
            heapq.heappush(heap, cooldown.popleft()[1])
    return time

print(task_scheduler_simulate(['A','A','A','B','B','B'], 2))  # 8

Masalah Stesen Minyak

Stesen Minyak (LeetCode 134): terdapat n stesen minyak dalam satu bulatan. Stesen i mempunyai minyak gas[i] dan kos cost[i] untuk bergerak ke stesen seterusnya. Bermula dengan tangki kosong, cari stesen mula yang membolehkan anda melengkapkan litar. Jika tiada stesen sedemikian, kembalikan -1. Masalah ini menjamin paling banyak satu jawapan yang sah jika jawapan itu wujud.

# Example:
gas  = [1, 2, 3, 4, 5]
cost = [3, 4, 5, 1, 2]
# net gain per station: gas[i] - cost[i]
net = [g - c for g, c in zip(gas, cost)]
print('Net gain per station:', net)  # [-2, -2, -2, 3, 3]
# Only possible start: station 3 (index 3)
# Tank: 0 +3=3 → 3-1=2 → 2+1=3-2=... let's verify
print('Sum of net:', sum(net))  # 1 > 0 means solution exists

Penyelesaian Tamak untuk Stesen Minyak

Algoritma tamak: (1) Jika jumlah minyak < jumlah kos, tiada penyelesaian wujud (kembalikan -1). (2) Jika tidak, tepat satu penyelesaian wujud. Cari penyelesaian itu dengan satu laluan: jejak tank (bahan api semasa) dan start (stesen mula calon). Jika tank < 0 selepas mengunjungi sebuah stesen, start semasa tidak dapat mencapai stesen tersebut — tetapkan semula tank = 0 dan tetapkan start = i + 1. start terakhir ialah jawapannya.

def can_complete_circuit(gas, cost):
    if sum(gas) < sum(cost):
        return -1  # impossible
    tank = 0
    start = 0
    for i in range(len(gas)):
        tank += gas[i] - cost[i]
        if tank < 0:
            tank = 0
            start = i + 1  # current start failed, try next
    return start

gas  = [1, 2, 3, 4, 5]
cost = [3, 4, 5, 1, 2]
print(can_complete_circuit(gas, cost))  # 3

gas2  = [2, 3, 4]
cost2 = [3, 4, 3]
print(can_complete_circuit(gas2, cost2))  # -1

Mengapa Titik Mula Tamak Itu Betul

Hujah ketepatan: jika tangki menjadi negatif selepas sampai ke stesen i dari start, maka tiada stesen antara start dengan i (termasuk kedua-duanya) boleh menjadi titik mula yang sah — semuanya mempunyai kurang bahan api apabila sampai ke stesen i berbanding jumlah yang tersedia jika bermula dari start. Jadi, kita boleh melangkau semuanya dengan selamat dan mencuba i+1. Oleh sebab penyelesaian wujud (jumlah minyak ≥ jumlah kos), calon akhir start mestilah berjaya.

# Proof sketch: why start=i+1 is correct after tank<0 at station i
# If we start at station j (start <= j <= i), tank at j is tank_from_start(j)
# After stations start..j: tank_from_j starts at 0, but we've already used gas[start..j-1]
# Starting at j means: tank_at_i = sum(net[j..i]) = sum(net[start..i]) - sum(net[start..j-1])
# Since sum(net[start..i]) < 0 AND sum(net[start..j-1]) >= 0 (no reset before i),
# tank_at_i when starting at j is even more negative → j cannot work either

def verify_gas_solution(gas, cost, start):
    tank = 0
    n = len(gas)
    for i in range(n):
        idx = (start + i) % n
        tank += gas[idx] - cost[idx]
        if tank < 0: return False
    return True

print(verify_gas_solution([1,2,3,4,5],[3,4,5,1,2], 3))  # True

Cuba Semua berbanding Tamak untuk Stesen Minyak

Kaedah cuba semua mencuba setiap stesen mula dan mensimulasikan keseluruhan litar — masa O(n²). Penyelesaian tamak satu laluan mengambil masa O(n) dan ruang O(1). Bagi tatasusunan 10⁵ stesen, perbezaannya ialah 10¹⁰ operasi berbanding 10⁵. Sifat matematik utama yang membolehkan kaedah tamak ialah: jika jumlah bersih bahan api tidak negatif, titik mula yang sah wujud, dan titik itu sentiasa merupakan stesen tepat selepas titik terakhir yang menyebabkan jumlah terkumpul menjadi negatif.

def brute_force_gas(gas, cost):
    n = len(gas)
    for start in range(n):
        tank = 0
        valid = True
        for i in range(n):
            idx = (start + i) % n
            tank += gas[idx] - cost[idx]
            if tank < 0: valid = False; break
        if valid: return start
    return -1

def greedy_gas(gas, cost):
    if sum(gas) < sum(cost): return -1
    tank = start = 0
    for i, (g, c) in enumerate(zip(gas, cost)):
        tank += g - c
        if tank < 0: tank = 0; start = i + 1
    return start

gas = [1,2,3,4,5]; cost = [3,4,5,1,2]
print('Brute:', brute_force_gas(gas,cost), '== Greedy:', greedy_gas(gas,cost))

Berkaitan: Kos Minimum untuk Melengkapkan Perjalanan

Masa Minimum untuk Melengkapkan Perjalanan (LeetCode 2187) ialah masalah carian perduaan pada ruang jawapan. Anda melakukan carian perduaan terhadap nilai masa T: diberikan masa T, bas dengan time[i] melengkapkan floor(T/time[i]) perjalanan. Jika jumlah perjalanan ≥ totalTrips, T mencukupi. Cari T minimum sedemikian. Ini menunjukkan bahawa pendekatan tamak boleh digunakan pada peringkat meta (mencari secara perduaan merentasi jawapan) apabila tiada peraturan tamak langsung pada peringkat objek.

def minimum_time(time, total_trips):
    def can_complete(t):
        return sum(t // bus for bus in time) >= total_trips
    
    lo, hi = 1, min(time) * total_trips  # upper bound
    while lo < hi:
        mid = (lo + hi) // 2
        if can_complete(mid):
            hi = mid
        else:
            lo = mid + 1
    return lo

print(minimum_time([1, 2, 3], 5))   # 3 (3/1=3 + 3/2=1 + 3/3=1 = 5)
print(minimum_time([2], 1))          # 2

Kes Sempadan dan Pengesahan

Kes sempadan penting untuk kedua-dua masalah: Penjadual Tugas — apabila tempoh rehat n=0, jawapannya hanyalah len(tasks) (tiada masa melahu diperlukan). Apabila semua tugas sama (contohnya, semua 'A'), slot melahu diisi tepat. Apabila tugas mempunyai banyak jenis berbeza, slot melahu mungkin 0 (tugas memenuhi semua bingkai). Stesen Minyak — apabila jumlah minyak sama tepat dengan jumlah kos, wujud tepat satu titik mula yang sah. Apabila satu stesen mempunyai minyak yang mencukupi untuk seluruh litar, stesen itu ialah jawapannya. Sentiasa sahkan jawapan tamak anda pada kes terdegenerat ini.

from collections import Counter

def least_interval(tasks, n):
    if n == 0: return len(tasks)  # no cooldown
    cnt = Counter(tasks)
    mf = max(cnt.values())
    mc = sum(1 for c in cnt.values() if c == mf)
    return max(len(tasks), (mf-1)*(n+1)+mc)

# Edge cases for task scheduler
print(least_interval(['A','A','A'], 2))   # 7: A _ _ A _ _ A
print(least_interval(['A','A','B','B'], 0)) # 4: no idle
print(least_interval(['A','B','C','D'], 3))  # 4: all diff, no idle needed

# Edge case for gas station
def gas_station(gas, cost):
    if sum(gas) < sum(cost): return -1
    tank = start = 0
    for i,(g,c) in enumerate(zip(gas,cost)):
        tank += g-c
        if tank < 0: tank=0; start=i+1
    return start

print(gas_station([5,1,2,3,4],[4,4,1,5,1]))  # 4

Pengecaman Corak T pamak

Kedua-dua Penjadual Tugas dan Stesen Minyak mengikut corak pendekatan tamak: (1) Kenal pasti kesesakan (tugas paling kerap / baki imbangan bahan api). (2) Buat keputusan satu laluan dengan pemboleh ubah berjalan (max_freq, tank). (3) Mulakan semula atau tetapkan semula apabila kekangan dilanggar. Masalah pendekatan tamak umum yang perlu diketahui: Pemilihan Aktiviti, Pengekodan Huffman, Beg Galas Pecahan, Permainan Lompat, Penjadual Tugas, Stesen Minyak, Penggabungan Selang. Setiap satunya mempunyai pembuktian melalui hujah pertukaran atau invarian matematik.

# Greedy pattern summary
# Task Scheduler:
#   Bottleneck: max frequency task
#   Formula: max(total_tasks, (max_freq-1)*(n+1)+max_count)
#   O(n) time, O(1) space

# Gas Station:
#   Bottleneck: running sum of (gas-cost) going negative
#   Reset start when tank < 0, valid if total sum >= 0
#   O(n) time, O(1) space

# Both avoid the need for DP by using a clever single-pass insight
from collections import Counter
def combined_demo(tasks, n, gas, cost):
    ti = max(len(tasks), (max(Counter(tasks).values())-1)*(n+1) +
             sum(1 for c in Counter(tasks).values() if c==max(Counter(tasks).values())))
    tank = start = 0
    gs = sum(g-c for g,c in zip(gas,cost)) >= 0
    return ti, start if gs else -1

Semakan Pantas

Uji pemahaman anda tentang konsep Struktur Data & Algoritma — Persediaan Temu Duga Pengekodan daripada pelajaran ini.

Ringkasan Pelajaran

Dalam pelajaran ini, anda mempelajari: jawapan Penjadual Tugas = max(total_tasks, (max_freq-1)*(n+1)+max_count) — diterbitkan dengan mengisi grid berasaskan bingkai menggunakan tugas paling kerap, Stesen Minyak menggunakan satu laluan, menetapkan semula start=i+1 setiap kali tank menjadi negatif, dan sah apabila jumlah minyak ≥ jumlah kos, dan kedua-dua masalah menggunakan masa O(n) dan ruang O(1) dengan mengenal pasti invarian matematik, bukannya melakukan carian menyeluruh. Seterusnya kita akan mengkaji templat Bahagi dan Takluk serta aplikasinya di luar pengisihan gabung.

Percuma untuk bermula

Pelajari Persediaan Temu Duga Pengaturcaraan dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
90
Pelajaran
360

Soalan Lazim

Adakah pelajaran “Penjadual Tugas dan Stesen Minyak” percuma?

Ya — teks penuh “Penjadual Tugas dan Stesen Minyak” boleh dibaca secara percuma di web ini. Untuk berlatih secara interaktif menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7, serta membuka kunci baki kursus Persediaan Temu Duga Pengaturcaraan, tingkat taraf kepada CoddyKit PRO. Kursus Persediaan Temu Duga Pengaturcaraan merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “Penjadual Tugas dan Stesen Minyak”?

Gunakan penaakulan tamak untuk masalah tempoh penyejukan penjadual tugas CPU dan masalah kebolehlaksanaan stesen minyak berbentuk bulatan. Anda berlatih Persediaan Temu Duga Pengaturcaraan menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan Persediaan Temu Duga Pengaturcaraan?

Tiada pengalaman terdahulu diperlukan. Pembelajaran Persediaan Temu Duga Pengaturcaraan di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 4 daripada 4.

Berapa lamakah pelajaran “Penjadual Tugas dan Stesen Minyak” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran Persediaan Temu Duga Pengaturcaraan ini?

Ya. Setiap pelajaran Persediaan Temu Duga Pengaturcaraan menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. Tamak berbanding DP: Bila Menggunakan Setiap Satu
  2. Penjadualan dan Penggabungan Selang
  3. Permainan Lompatan I dan II
  4. Penjadual Tugas dan Stesen Minyak
← Kembali ke Persediaan Temu Duga Pengaturcaraan