0Pricing
Coding Interview Prep · Ders

Görev Çizelgeleyici ve Benzin İstasyonu

CPU görev çizelgeleyicisindeki soğuma süresi problemine ve dairesel benzin istasyonu uygunluk problemine açgözlü akıl yürütmeyi uygulayın.

Görev Çizelgeleyici ve Benzin İstasyonu, CoddyKit'te ücretsiz bir Coding Interview Prep dersidir. Bu, 4 dersinin 4. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, Coding Interview Prep öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. Coding Interview Prep kursu toplamda 4 dersten oluşur.

Görev Zamanlayıcı Problemi

Görev Zamanlayıcı (LeetCode 621): her biri A-Z arasında etiketlenmiş CPU görevlerinden oluşan bir liste ve n uzunluğunda bir soğuma süresi verildiğinde, tüm görevleri tamamlamak için gereken minimum CPU aralığı sayısını bulun. Aynı görev yeniden çalıştırılmadan önce en az n aralık beklemelidir. Boş aralıklara izin verilir. Soğuma süresi 2 olan ['A','A','A','B','B','B'] görevleri için yanıt 8'dir: 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')

Görev Zamanlayıcı İçin Açgözlü Formül

Temel fikir şudur: toplam süreyi en sık görülen görev belirler. En sık görülen görev f kez görünüyorsa ve sıklığı f olan görevlerin sayısı max_count ise süre max(len(tasks), (f-1) * (n+1) + max_count) olur. Formül şöyledir: f-1 adet, her biri n+1 boyutunda çerçeve oluşturun, bunları diğer görevlerle doldurun ve son döngüyü ekleyin. Diğer görevler tüm boş yuvaları dolduruyorsa (çok sayıda farklı görev varsa), tüm görevleri boş süre olmadan doğrudan çalıştırın.

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

Formül Neden Çalışır?

Zamanlamayı n+1 sütunlu bir ızgara olarak görselleştirin (bir görev yuvası + n soğuma yuvası). En sık görülen A görevinin (sıklık f) f satıra ihtiyacı vardır. İlk ve son görünüm arasında, her biri n+1 yuva içeren f-1 tam çerçeve bulunur. Buna, maksimum sıklığa sahip tüm görevleri içeren son kısmi çerçeveyi ekleyin. Yeterli sayıda farklı görev varsa tüm boş yuvaları doldururlar ve gerçek görev sayısı çerçeve süresini aşar — iki değerden büyük olanı alın.

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

Yığınla Benzetim Alternatifi

Yığın tabanlı bir benzetim, yalnızca sayıyı değil, gerçek zamanlamayı da verir. Her adımda kullanılabilir görevler arasından en sık olanı alın (maksimum yığını). Çalıştırdıktan sonra soğuma süresini uygulayın: görevi n adım sonrasına kadar yeniden eklemeyin. Soğuyan görevleri izlemek için bir kuyruk kullanın. Bu yaklaşım, k farklı görevin sayısı olmak üzere O(toplam_süre × log k) zamanda çalışır. Doğru olsa da formül daha hızlıdır. Her ikisini de bilin — mülakat yapanlar zamanlamanın kendisini isteyebilir.

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

Benzin İstasyonu Problemi

Benzin İstasyonu (LeetCode 134): bir çember üzerinde n benzin istasyonu vardır. i istasyonunda gas[i] miktarında benzin bulunur ve bir sonraki istasyona gitmenin maliyeti cost[i] kadardır. Depo boşken başlayarak turu tamamlayabileceğiniz başlangıç istasyonunu bulun. Böyle bir istasyon yoksa -1 döndürün. Problem, geçerli bir yanıt varsa en fazla bir tane olacağını garanti eder.

# 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

Benzin İstasyonu İçin Açgözlü Çözüm

Açgözlü algoritma: (1) Toplam benzin < toplam maliyet ise çözüm yoktur (-1 döndürün). (2) Aksi hâlde tam olarak bir çözüm vardır. Çözümü tek geçişte bulun: tank (mevcut yakıt) ve start (aday başlangıç istasyonu) değerlerini izleyin. Bir istasyonu ziyaret ettikten sonra tank < 0 olursa mevcut start o istasyona ulaşamaz — tank = 0 değerini atayın ve start = i + 1 yapın. Son start yanıt olacaktır.

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

Açgözlü Başlangıç Neden Doğrudur?

Doğruluk argümanı: start konumundan i istasyonuna ulaştıktan sonra depo negatife düşerse, start ile i arasındaki (ikisi de dahil) hiçbir istasyon geçerli bir başlangıç noktası olamaz — bu istasyonların tümü i istasyonuna ulaştıklarında, start konumundan başlanması durumunda bulunacak yakıttan daha az yakıta sahip olur. Bu nedenle hepsini güvenle atlayıp i+1 ile deneriz. Bir çözüm bulunduğundan (toplam benzin ≥ toplam maliyet), son aday start mutlaka işe yarar.

# 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

Benzin İstasyonu İçin Kaba Kuvvet ve Açgözlü Yaklaşım

Kaba kuvvet, her başlangıç istasyonunu dener ve turun tamamını benzetir — O(n²) zaman. Tek geçişli açgözlü çözüm ise O(n) zaman ve O(1) alan kullanır. 10⁵ istasyondan oluşan bir dizi için fark, 10¹⁰ işleme karşı 10⁵ işlemdir. Açgözlü yaklaşımı mümkün kılan temel matematiksel özellik şudur: toplam net yakıt negatif değilse geçerli bir başlangıç vardır ve bu başlangıç, birikimli toplamın negatife düştüğü son noktanın hemen sonraki istasyonudur.

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

İlgili: Gezileri Tamamlamak İçin Minimum Maliyet

Gezileri Tamamlamak İçin Minimum Süre (LeetCode 2187), yanıt uzayında ikili arama problemidir. Zaman değeri T üzerinde ikili arama yaparsınız: T süresi verildiğinde, time[i] süresine sahip otobüsler floor(T/time[i]) gezi tamamlar. Toplam gezi sayısı ≥ totalTrips ise T yeterlidir. Bu koşulu sağlayan en küçük T değerini bulun. Bu örnek, nesne düzeyinde doğrudan bir açgözlü kural bulunmadığında, üst düzeyde (yanıtlar üzerinde ikili arama yaparak) açgözlü yaklaşımın uygulanabileceğini gösterir.

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

Sınır Durumları ve Doğrulama

Her iki problem için önemli sınır durumları: Görev Zamanlayıcı — soğuma süresi n=0 olduğunda yanıt basitçe len(tasks) olur; boşta beklemek gerekmez. Tüm görevler aynı olduğunda (örneğin hepsi 'A' olduğunda), boş yuvalar tam olarak doldurulur. Çok sayıda farklı görev türü olduğunda boş yuva sayısı 0 olabilir; görevler tüm çerçeveleri doldurur. Benzin İstasyonu — toplam benzin toplam maliyete tam olarak eşitse, tam bir geçerli başlangıç noktası vardır. Tek bir istasyonda tüm turu tamamlamaya yetecek kadar benzin varsa, yanıt o istasyondur. Açgözlü yaklaşımınızın yanıtını her zaman bu özel durumlarda doğrulayın.

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

Açgözlü Kalıbı Tanıma

Görev Zamanlayıcı ve Benzin İstasyonu problemleri şu açgözlü kalıbı izler: (1) Darboğazı belirleyin (en sık tekrarlanan görev / net yakıt dengesi). (2) Güncel bir değişken kullanarak tek geçişte karar verin (en yüksek sıklık, yakıt deposu). (3) Bir kısıt ihlal edildiğinde yeniden başlatın veya sıfırlayın. Bilinmesi gereken yaygın açgözlü problemler şunlardır: Etkinlik Seçimi, Huffman Kodlaması, Kesirli Sırt Çantası, Zıplama Oyunu, Görev Zamanlayıcı, Benzin İstasyonu ve Aralıkları Birleştirme. Bunların her biri, değiş tokuş argümanıyla veya matematiksel bir değişmezle kanıtlanabilir.

# 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

Hızlı Kontrol

Bu dersteki Veri Yapıları ve Algoritmalar — Kodlama Mülakatına Hazırlık kavramlarını anlayıp anlamadığınızı sınayın.

Ders Özeti

Bu derste şunları öğrendiniz: Görev Zamanlayıcı yanıtı = max(total_tasks, (max_freq-1)*(n+1)+max_count) — en sık tekrarlanan görevle çerçeve tabanlı tabloların doldurulmasından türetilir, Benzin İstasyonu tek geçiş kullanır; tank negatif olduğunda start=i+1 değerine sıfırlanır ve toplam benzin ≥ toplam maliyet olduğunda geçerlidir ve her iki problem de kapsamlı arama yerine matematiksel bir değişmezi belirleyerek O(n) zaman ve O(1) alan kullanır. Sırada Böl ve Yönet şablonunu ve bunun merge sıralamasının ötesindeki uygulamalarını inceleyeceğiz.

Sıkça Sorulan Sorular

“Görev Çizelgeleyici ve Benzin İstasyonu” dersi ücretsiz mi?

Evet — “Görev Çizelgeleyici ve Benzin İstasyonu” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve Coding Interview Prep kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. Coding Interview Prep kursu toplamda 4 dersten oluşur.

“Görev Çizelgeleyici ve Benzin İstasyonu” dersinde ne öğreneceğim?

CPU görev çizelgeleyicisindeki soğuma süresi problemine ve dairesel benzin istasyonu uygunluk problemine açgözlü akıl yürütmeyi uygulayın. Coding Interview Prep ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.

Coding Interview Prep öğrenmeye başlamak için deneyim gerekli mi?

Önceden deneyim gerekmez. CoddyKit'te Coding Interview Prep, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 4. dersidir.

“Görev Çizelgeleyici ve Benzin İstasyonu” dersi ne kadar sürer?

Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.

Bu Coding Interview Prep dersinde kod yazıp çalıştırabilir miyim?

Evet. Her Coding Interview Prep dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.

Bu kursun tüm dersleri

  1. Açgözlü Yaklaşım mı DP mi: Hangisi Ne Zaman Kullanılır
  2. Aralık Çizelgeleme ve Birleştirme
  3. Sıçrama Oyunu I ve II
  4. Görev Çizelgeleyici ve Benzin İstasyonu
← Coding Interview Prep Sayfasına Dön