Sliding Window untuk Substring
Implementasikan sliding window berukuran variabel untuk menemukan substring terpanjang tanpa karakter berulang dan window minimum yang memuat semua karakter target.
Sliding Window untuk Substring 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.
Konsep Jendela Geser
Jendela geser mempertahankan sublarik (atau subteks) di antara penunjuk kiri dan kanan. Alih-alih menghitung ulang sifat setiap sublarik yang mungkin dari awal dalam O(n²), jendela diperluas ke kanan dengan menambahkan satu elemen dan dipersempit dari kiri dengan menghapus satu elemen, sambil mempertahankan status kumulatif dalam O(1) untuk setiap langkah. Hasilnya adalah algoritma O(n). Jendela ini disebut “geser” karena bergerak maju melalui larik tanpa pernah bergerak mundur.
# Fixed-size window sum: O(n) after O(k) setup
def max_sum_window(nums, k):
window_sum = sum(nums[:k]) # initial window
best = window_sum
for i in range(k, len(nums)):
window_sum += nums[i] # add new right
window_sum -= nums[i - k] # remove old left
best = max(best, window_sum)
return best
print(max_sum_window([2,1,5,1,3,2], 3)) # 9 ([5,1,3])Ukuran Jendela Tetap dan Variabel
Ada dua variasi jendela geser. Dalam jendela berukuran tetap, kedua penunjuk bergerak dengan kecepatan yang sama dan jendela selalu memiliki tepat k elemen. Dalam jendela berukuran variabel, penunjuk kanan diperluas secara rakus dan penunjuk kiri hanya dipersempit ketika jendela melanggar suatu batasan. Jendela berukuran variabel menyelesaikan masalah seperti “subteks terpanjang tanpa karakter berulang”, ketika ukuran jendela optimal belum diketahui sebelumnya.
# Variable window: longest substring with at most k distinct chars
def longest_k_distinct(s, k):
from collections import defaultdict
freq = defaultdict(int)
left = 0
best = 0
for right in range(len(s)):
freq[s[right]] += 1
while len(freq) > k: # window invalid: shrink
freq[s[left]] -= 1
if freq[s[left]] == 0:
del freq[s[left]]
left += 1
best = max(best, right - left + 1)
return best
print(longest_k_distinct('eceba', 2)) # 3 ('ece')
print(longest_k_distinct('aa', 1)) # 2Subteks Terpanjang Tanpa Pengulangan
Ini adalah masalah jendela geser variabel yang paling terkenal. Gunakan himpunan untuk melacak karakter dalam jendela saat ini. Perluas ke kanan; ketika menemukan duplikat, perkecil dari kiri sampai duplikat tersebut terhapus. Versi yang lebih cepat menggunakan peta hash yang menyimpan indeks terbaru setiap karakter, sehingga penunjuk kiri dapat melompati duplikat dalam satu langkah, bukan bergerak sedikit demi sedikit.
def length_of_longest_substring(s):
char_idx = {} # char -> last seen index
left = 0
best = 0
for right, c in enumerate(s):
if c in char_idx and char_idx[c] >= left:
left = char_idx[c] + 1 # jump past duplicate
char_idx[c] = right
best = max(best, right - left + 1)
return best
print(length_of_longest_substring('abcabcbb')) # 3 ('abc')
print(length_of_longest_substring('bbbbb')) # 1
print(length_of_longest_substring('pwwkew')) # 3 ('wke')Subteks dengan Jendela Minimum
Diberikan teks s dan t, temukan jendela terkecil dalam s yang berisi semua karakter t. Gunakan dua peta frekuensi: need (karakter yang diperlukan) dan have (karakter dalam jendela saat ini yang memenuhi persyaratan). Lacak berapa banyak karakter unik dalam t yang sudah terpenuhi (penghitung formed). Perluas ke kanan untuk memasukkan karakter; ketika seluruh t sudah tercakup, perkecil dari kiri untuk meminimalkan jendela. Waktu O(|s| + |t|).
from collections import Counter
def min_window(s, t):
if not t or not s: return ''
need = Counter(t)
have = {}
formed = 0
required = len(need)
left = 0
best = float('inf'), 0, 0
for right, c in enumerate(s):
have[c] = have.get(c, 0) + 1
if c in need and have[c] == need[c]:
formed += 1
while formed == required:
if right - left + 1 < best[0]:
best = right - left + 1, left, right
have[s[left]] -= 1
if s[left] in need and have[s[left]] < need[s[left]]:
formed -= 1
left += 1
return s[best[1]:best[2]+1] if best[0] != float('inf') else ''
print(min_window('ADOBECODEBANC', 'ABC')) # 'BANC'Pola Jendela Geser
Sebagian besar masalah jendela geser berukuran variabel mengikuti pola yang sama: perluas ke kanan untuk memasukkan karakter baru, perbarui status jendela, periksa validitasnya, dan jika tidak valid, perkecil dari kiri sampai kembali valid. Wawasan utamanya adalah penunjuk kiri hanya bergerak maju — tidak pernah mundur — sehingga total pekerjaan untuk semua langkah penyempitan adalah O(n). Jendela mengunjungi setiap elemen paling banyak dua kali (sekali saat ditambahkan dan sekali saat dihapus).
def sliding_window_template(s, condition_check, update_state, remove_state):
"""
Generic sliding window skeleton.
Adapt condition_check, update_state, remove_state per problem.
"""
left = 0
state = {} # or whatever state you need
best = 0
for right in range(len(s)):
update_state(state, s[right]) # expand window
while not condition_check(state): # window invalid
remove_state(state, s[left]) # shrink window
left += 1
best = max(best, right - left + 1)
return bestPermutasi dalam Teks
Periksa apakah ada permutasi pola p yang muncul sebagai subteks dalam s. Pemeriksaan permutasi setara dengan jendela yang memiliki frekuensi karakter yang sama seperti p. Pertahankan jendela geser yang tepat berisi len(p) karakter dan bandingkan hitungan frekuensinya. Membandingkan seluruh objek penghitung pada setiap langkah memerlukan O(26) (konstan untuk bahasa Inggris huruf kecil), sehingga totalnya O(n × 26) = O(n).
from collections import Counter
def check_inclusion(p, s):
if len(p) > len(s): return False
need = Counter(p)
window = Counter(s[:len(p)])
if need == window: return True
for right in range(len(p), len(s)):
left = right - len(p)
window[s[right]] += 1
window[s[left]] -= 1
if window[s[left]] == 0:
del window[s[left]]
if window == need:
return True
return False
print(check_inclusion('ab', 'eidbaooo')) # True ('ba')
print(check_inclusion('ab', 'eidboaoo')) # FalseSubteks Anagram: Hitung Semuanya
Temukan semua indeks awal anagram p dalam s. Teknik ini sama dengan teknik jendela tetap pada masalah permutasi dalam teks, tetapi alih-alih mengembalikan True pada kecocokan pertama, kita mengumpulkan semua posisi yang cocok. Ukuran jendela tetap len(p); geser jendela tersebut melintasi s dan bandingkan hitungan frekuensi pada setiap langkah.
from collections import Counter
def find_anagrams(s, p):
result = []
need = Counter(p)
k = len(p)
window = Counter(s[:k])
if window == need:
result.append(0)
for right in range(k, len(s)):
window[s[right]] += 1
left_char = s[right - k]
window[left_char] -= 1
if window[left_char] == 0:
del window[left_char]
if window == need:
result.append(right - k + 1)
return result
print(find_anagrams('cbaebabacd', 'abc')) # [0, 6]Subteks Terpanjang dengan Maksimal 2 Karakter Berbeda
Ini adalah variasi jendela geser: temukan subteks terpanjang yang berisi paling banyak 2 karakter berbeda. Pertahankan peta frekuensi karakter dalam jendela saat ini. Ketika peta tersebut memiliki lebih dari 2 entri, gerakkan penunjuk kiri ke kanan (kurangi frekuensi, hapus jika nol) sampai batasannya kembali terpenuhi. Ini adalah kasus khusus dari “paling banyak k karakter berbeda” dengan k=2.
def longest_substring_two_distinct(s):
from collections import defaultdict
freq = defaultdict(int)
left = 0
best = 0
for right, c in enumerate(s):
freq[c] += 1
while len(freq) > 2:
freq[s[left]] -= 1
if freq[s[left]] == 0:
del freq[s[left]]
left += 1
best = max(best, right - left + 1)
return best
print(longest_substring_two_distinct('eceba')) # 3 ('ece')
print(longest_substring_two_distinct('ccaabbb')) # 5 ('aabbb')Maksimum Jendela Geser
Temukan nilai maksimum dalam setiap jendela berukuran k. Pemeriksaan secara langsung terhadap maksimum setiap jendela memerlukan O(n×k). Pendekatan optimal menggunakan antrean dua ujung monotonik yang berisi indeks: pertahankan antrean menurun sehingga bagian depannya selalu berisi indeks maksimum jendela saat ini. Hapus indeks dari bagian depan ketika indeks tersebut keluar dari jendela, dan hapus indeks dari bagian belakang ketika elemen yang lebih besar masuk. Total waktu O(n).
from collections import deque
def max_sliding_window(nums, k):
dq = deque() # stores indices, decreasing values
result = []
for i, n in enumerate(nums):
# Remove indices outside window
while dq and dq[0] < i - k + 1:
dq.popleft()
# Maintain decreasing order
while dq and nums[dq[-1]] < n:
dq.pop()
dq.append(i)
if i >= k - 1: # window is full
result.append(nums[dq[0]])
return result
print(max_sliding_window([1,3,-1,-3,5,3,6,7], 3))
# [3, 3, 5, 5, 6, 7]Kapan Menggunakan Jendela Geser
Gunakan jendela geser ketika Anda melihat:
- Subteks / sublarik dengan batasan (panjang maksimum, jumlah = k, paling banyak k karakter berbeda)
- Ukuran jendela tetap dengan suatu agregasi (maksimum, jumlah, frekuensi)
- Pertanyaan tentang rentang berurutan (bukan himpunan bagian sembarang)
# Recognising sliding window problems:
# 1. Fixed window: 'maximum average of subarray of length k'
def max_avg(nums, k):
s = sum(nums[:k])
best = s
for i in range(k, len(nums)):
s += nums[i] - nums[i-k]
best = max(best, s)
return best / k
print(max_avg([1,12,-5,-6,50,3], 4)) # 12.75
# 2. Variable window: 'smallest subarray with sum >= target'
def min_sub_len(target, nums):
left = s = 0
best = float('inf')
for right, n in enumerate(nums):
s += n
while s >= target:
best = min(best, right - left + 1)
s -= nums[left]; left += 1
return 0 if best == float('inf') else best
print(min_sub_len(7, [2,3,1,2,4,3])) # 2Menghitung Jendela Valid: Maksimal K
Beberapa masalah meminta jumlah sublarik yang memenuhi suatu kondisi. Trik yang berguna adalah menghitung sublarik dengan paling banyak k karakter berbeda, lalu mengurangkannya untuk memperoleh tepat k: exactly(k) = at_most(k) - at_most(k-1). Setiap pemanggilan at_most memerlukan O(n), sehingga totalnya O(n). Fungsi at_most menghitung jendela yang jumlah karakter berbedanya tidak melebihi k dengan menjumlahkan right - left + 1 (semua titik kiri yang valid untuk setiap titik kanan).
from collections import defaultdict
def subarrays_at_most_k(s, k):
freq = defaultdict(int)
left = 0
count = 0
for right, c in enumerate(s):
freq[c] += 1
while len(freq) > k:
freq[s[left]] -= 1
if freq[s[left]] == 0: del freq[s[left]]
left += 1
count += right - left + 1 # all valid windows ending at right
return count
def subarrays_exactly_k(s, k):
return subarrays_at_most_k(s, k) - subarrays_at_most_k(s, k-1)
print(subarrays_exactly_k('araaci', 2)) # 9Uji Singkat
Ujilah pemahaman Anda tentang konsep Struktur Data & Algoritma — Persiapan Wawancara Pemrograman dari pelajaran ini.
Rangkuman Pelajaran
Dalam pelajaran ini Anda mempelajari: jendela geser menghilangkan O(n²) dengan mempertahankan status jendela kumulatif yang diperbarui dalam O(1) saat elemen masuk dan keluar, jendela berukuran tetap menggerakkan kedua penunjuk dengan kecepatan yang sama; jendela berukuran variabel memperluas sisi kanan secara rakus dan hanya mempersempit sisi kiri ketika suatu batasan dilanggar, dan subteks dengan jendela minimum serta permutasi dalam teks sama-sama menggunakan status jendela berbasis peta frekuensi dengan penghitung yang melacak berapa banyak karakter yang diperlukan dan saat ini sudah terpenuhi. Selanjutnya kita akan mempelajari anagram dan peta frekuensi karakter.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Sliding Window untuk Substring” gratis?
Ya — teks lengkap “Sliding Window untuk Substring” 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 “Sliding Window untuk Substring”?
Implementasikan sliding window berukuran variabel untuk menemukan substring terpanjang tanpa karakter berulang dan window minimum yang memuat semua karakter target. 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 “Sliding Window untuk Substring” 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
- API String Python untuk Wawancara
- Sliding Window untuk Substring
- Anagram dan Peta Frekuensi Karakter
- Pengodean String, Pembalikan, dan Palindrome