Tetingkap Gelangsar untuk Subrentetan
Laksanakan tetingkap gelangsar bersaiz berubah untuk mencari subrentetan terpanjang tanpa aksara berulang dan tetingkap minimum yang mengandungi semua aksara sasaran.
Tetingkap Gelangsar untuk Subrentetan ialah pelajaran Persediaan Temu Duga Pengaturcaraan percuma di CoddyKit. Ini ialah pelajaran 2 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.
Konsep Tetingkap Gelongsor
Tetingkap gelongsor mengekalkan sublarik (atau subrentetan) antara penuding kiri dan kanan. Daripada mengira semula sifat setiap sublarik yang mungkin dari awal dalam O(n²), tetingkap mengembang ke kanan dengan menambah satu unsur dan mengecut ke kiri dengan membuang satu unsur, sambil mengekalkan keadaan semasa dalam O(1) bagi setiap langkah. Hasilnya ialah algoritma O(n). Tetingkap ini dipanggil 'gelongsor' kerana ia bergerak ke hadapan melalui tatasusunan tanpa bergerak ke belakang.
# 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])Saiz Tetingkap Tetap berbanding Berubah
Terdapat dua variasi tetingkap gelongsor. Dalam tetingkap bersaiz tetap, kedua-dua penuding bergerak pada kadar yang sama dan tetingkap sentiasa mempunyai tepat k unsur. Dalam tetingkap bersaiz berubah, penuding kanan mengembang secara agresif dan penuding kiri mengecut hanya apabila tetingkap melanggar kekangan. Tetingkap bersaiz berubah menyelesaikan masalah seperti 'subrentetan terpanjang tanpa aksara berulang' apabila saiz tetingkap optimum belum diketahui.
# 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)) # 2Subrentetan Terpanjang Tanpa Pengulangan
Ini ialah masalah tetingkap gelongsor berubah yang paling terkenal. Gunakan himpunan untuk menjejaki aksara dalam tetingkap semasa. Kembangkan ke kanan; apabila pendua ditemui, kecilkan dari kiri sehingga pendua itu dibuang. Versi yang lebih pantas menggunakan peta cincang yang menyimpan indeks terkini bagi setiap aksara, lalu membolehkan penuding kiri melangkaui pendua dalam satu langkah dan bukannya 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')Subrentetan Tetingkap Minimum
Diberi rentetan s dan t, cari tetingkap terkecil dalam s yang mengandungi semua aksara t. Gunakan dua peta frekuensi: need (aksara yang diperlukan) dan have (aksara dalam tetingkap semasa yang memenuhi keperluan). Jejaki bilangan aksara unik dalam t yang telah dipenuhi (pembilang formed). Kembangkan ke kanan untuk memasukkan aksara; apabila seluruh t telah diliputi, kecilkan dari kiri untuk meminimumkan tetingkap. Masa 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'Rangka Tetingkap Gelongsor
Kebanyakan masalah tetingkap gelongsor berubah berkongsi rangka yang sama: kembangkan ke kanan untuk memasukkan aksara baharu, kemas kini keadaan tetingkap, semak kesahan, dan jika tidak sah, kecilkan dari kiri sehingga kembali sah. Wawasan utamanya ialah penuding kiri hanya bergerak ke hadapan — ia tidak pernah bergerak ke belakang — maka jumlah kerja bagi semua langkah pengecilan ialah O(n). Tetingkap memproses setiap unsur paling banyak dua kali, iaitu sekali ketika ditambah dan sekali ketika dibuang.
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 Rentetan
Semak sama ada sebarang permutasi corak p wujud sebagai subrentetan s. Semakan permutasi bersamaan dengan mencari tetingkap yang mempunyai frekuensi aksara yang sama seperti p. Kekalkan tetingkap yang mengandungi tepat len(p) aksara dan bandingkan kiraan frekuensi. Membandingkan keseluruhan objek pengira pada setiap langkah memerlukan O(26), iaitu pemalar bagi bahasa Inggeris huruf kecil, lalu memberikan O(n × 26) = O(n) secara keseluruhan.
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')) # FalseSubrentetan Anagram: Kira Kesemuanya
Cari semua indeks permulaan anagram p dalam s. Ini menggunakan teknik tetingkap tetap yang sama seperti permutasi dalam rentetan, tetapi bukannya mengembalikan Benar pada padanan pertama, kita mengumpulkan semua kedudukan yang sepadan. Saiz tetingkap ditetapkan kepada len(p); gerakkan tetingkap merentasi s dan bandingkan kiraan 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]Subrentetan Terpanjang dengan Tidak Lebih daripada 2 Aksara Berbeza
Ini ialah variasi tetingkap gelongsor: cari subrentetan terpanjang yang mengandungi tidak lebih daripada 2 aksara berbeza. Kekalkan peta frekuensi aksara dalam tetingkap semasa. Apabila peta mempunyai lebih daripada 2 entri, gerakkan penuding kiri ke kanan, kurangkan frekuensi dan padamkan entri jika nilainya sifar, sehingga kekangan dipenuhi semula. Ini ialah kes khas masalah 'paling banyak k aksara berbeza' 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 Tetingkap Gelongsor
Cari nilai maksimum dalam setiap tetingkap bersaiz k. Semakan secara kasar bagi maksimum setiap tetingkap mengambil masa O(n×k). Pendekatan optimum menggunakan dek monotonik yang menyimpan indeks: kekalkan dek dalam susunan menurun supaya bahagian hadapan sentiasa mengandungi indeks maksimum tetingkap semasa. Buang indeks dari hadapan apabila indeks tersebut keluar dari tetingkap, dan buang indeks dari belakang apabila unsur yang lebih besar masuk. Jumlah masa ialah 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]Bilakah Perlu Menggunakan Tetingkap Gelongsor
Gunakan tetingkap gelongsor apabila anda melihat:
- Subrentetan / sublarik dengan kekangan (panjang maksimum, jumlah = k, paling banyak k aksara berbeza)
- Saiz tetingkap tetap dengan pengagregatan (maksimum, jumlah, frekuensi)
- Soalan tentang julat bersebelahan (bukan subset sewenang-wenangnya)
# 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])) # 2Mengira Tetingkap Sah: Paling Banyak K
Sesetengah masalah meminta bilangan sublarik yang memenuhi sesuatu syarat. Satu helah yang berguna ialah mengira sublarik dengan paling banyak k aksara berbeza, kemudian menolaknya untuk mendapatkan tepat k: exactly(k) = at_most(k) - at_most(k-1). Setiap panggilan kepada fungsi tersebut mengambil masa O(n), lalu jumlah masa ialah O(n). Fungsi itu mengira tetingkap yang bilangan aksara berbezanya tidak melebihi k dengan menjumlahkan right - left + 1 (semua titik kiri yang sah bagi 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)) # 9Semakan Pantas
Uji pemahaman anda tentang konsep Struktur Data & Algoritma — Persediaan Temu Duga Pengekodan daripada pelajaran ini.
Rumusan Pelajaran
Dalam pelajaran ini, anda mempelajari: tetingkap gelongsor menghapuskan O(n²) dengan mengekalkan keadaan tetingkap semasa yang dikemas kini dalam O(1) apabila unsur masuk dan keluar, tetingkap bersaiz tetap menggerakkan kedua-dua penuding pada kadar yang sama; tetingkap bersaiz berubah mengembang ke kanan secara agresif dan mengecut ke kiri hanya apabila kekangan dilanggar, dan subrentetan tetingkap minimum serta permutasi dalam rentetan kedua-duanya menggunakan keadaan tetingkap berasaskan peta frekuensi dengan pembilang yang menjejaki bilangan aksara yang diperlukan dan telah dipenuhi. Seterusnya, kita akan meneroka anagram dan peta frekuensi aksara.
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 “Tetingkap Gelangsar untuk Subrentetan” percuma?
Ya — teks penuh “Tetingkap Gelangsar untuk Subrentetan” 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 “Tetingkap Gelangsar untuk Subrentetan”?
Laksanakan tetingkap gelangsar bersaiz berubah untuk mencari subrentetan terpanjang tanpa aksara berulang dan tetingkap minimum yang mengandungi semua aksara sasaran. 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 2 daripada 4.
Berapa lamakah pelajaran “Tetingkap Gelangsar untuk Subrentetan” 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
- API Rentetan Python untuk Temu Duga
- Tetingkap Gelangsar untuk Subrentetan
- Anagram dan Peta Kekerapan Aksara
- Pengekodan Rentetan, Pembalikan dan Palindrom