Sliding Window für Teilstrings
Implementieren Sie ein Sliding Window variabler Größe, um den längsten Teilstring ohne wiederholte Zeichen und das kleinste Fenster mit allen Zielzeichen zu finden.
Sliding Window für Teilstrings ist eine kostenlose Coding Interview Prep-Lektion auf CoddyKit. Dies ist Lektion 2 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Coding Interview Prep-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Coding Interview Prep-Kurs umfasst insgesamt 4 Lektionen.
Das Sliding-Window-Konzept
Ein Sliding Window umfasst ein Teilarray (oder einen Teilstring) zwischen einem linken und einem rechten Zeiger. Statt die Eigenschaften jedes möglichen Teilarrays von Grund auf in O(n²) neu zu berechnen, wird das Fenster nach rechts erweitert, indem ein Element hinzugefügt wird, und nach links verkleinert, indem ein Element entfernt wird. Dabei wird ein laufender Zustand pro Schritt in O(1) aktualisiert. Das Ergebnis ist ein O(n)-Algorithmus. Das Fenster heißt „Sliding Window“, weil es sich durch das Array vorwärtsbewegt, ohne rückwärts zu gehen.
# 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])Feste und variable Fenstergröße
Es gibt zwei Varianten des Sliding Window. Bei einem Fenster fester Größe bewegen sich beide Zeiger im gleichen Tempo weiter, und das Fenster enthält immer genau k Elemente. Bei einem Fenster variabler Größe wird der rechte Zeiger gierig erweitert, während der linke Zeiger nur dann nachgezogen wird, wenn das Fenster eine Bedingung verletzt. Fenster variabler Größe lösen Probleme wie „längster Teilstring ohne sich wiederholende Zeichen“, bei denen die optimale Fenstergröße im Voraus unbekannt ist.
# 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)) # 2Längster Teilstring ohne Wiederholungen
Dies ist das bekannteste Problem mit einem variablen Sliding Window. Verwenden Sie ein Set, um die Zeichen im aktuellen Fenster zu verfolgen. Erweitern Sie das Fenster nach rechts; sobald ein Duplikat gefunden wird, verkleinern Sie es von links, bis das Duplikat entfernt ist. Eine schnellere Variante verwendet eine Hashmap, in der der jeweils letzte Index jedes Zeichens gespeichert wird. Dadurch kann der linke Zeiger in einem Schritt hinter das Duplikat springen, statt schrittweise voranzurücken.
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')Kleinstes Teilstring-Fenster
Gegeben sind die Strings s und t. Finden Sie das kleinste Fenster in s, das alle Zeichen von t enthält. Verwenden Sie zwei Häufigkeitsmaps: need (benötigte Zeichen) und have (Zeichen im aktuellen Fenster, die die Anforderungen erfüllen). Verfolgen Sie mit einem Zähler formed, wie viele eindeutige Zeichen aus t die Anforderungen erfüllen. Erweitern Sie das Fenster nach rechts, um Zeichen einzubeziehen. Sobald t vollständig enthalten ist, verkleinern Sie das Fenster von links, um es zu minimieren. Laufzeit: 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'Sliding-Window-Vorlage
Die meisten Probleme mit einem variablen Sliding Window folgen einer Vorlage: Erweitern Sie das Fenster nach rechts, um das neue Zeichen einzubeziehen, aktualisieren Sie den Fensterzustand, prüfen Sie die Gültigkeit und verkleinern Sie das Fenster bei einer ungültigen Bedingung von links, bis es wieder gültig ist. Die entscheidende Erkenntnis ist, dass sich der linke Zeiger nur vorwärts bewegt — niemals rückwärts — und die gesamte Arbeit über alle Verkleinerungsschritte hinweg daher O(n) beträgt. Das Fenster besucht jedes Element höchstens zweimal: einmal beim Hinzufügen und einmal beim Entfernen.
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 bestPermutation in einem String
Prüfen Sie, ob eine beliebige Permutation des Musters p als Teilstring in s vorkommt. Eine Permutationsprüfung entspricht einem Fenster mit denselben Zeichenhäufigkeiten wie p. Halten Sie ein Sliding Window mit genau len(p) Zeichen aufrecht und vergleichen Sie die Häufigkeitszählungen. Der Vergleich vollständiger Counter-Objekte benötigt pro Schritt O(26) — bei englischen Kleinbuchstaben eine Konstante —, sodass insgesamt O(n × 26) = O(n) entsteht.
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')) # FalseAnagramm-Teilstrings: alle zählen
Finden Sie alle Startindizes der Anagramme von p in s. Dies ist dieselbe Technik mit einem Fenster fester Größe wie bei „Permutation in einem String“, aber statt beim ersten Treffer True zurückzugeben, sammeln wir alle passenden Positionen. Die Fenstergröße ist auf len(p) festgelegt. Wir verschieben das Fenster über s und vergleichen bei jedem Schritt die Häufigkeitszählungen.
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]Längster Teilstring mit höchstens 2 verschiedenen Zeichen
Eine Variante des Sliding Window: Finden Sie den längsten Teilstring, der höchstens 2 verschiedene Zeichen enthält. Halten Sie eine Häufigkeitsmap der Zeichen im aktuellen Fenster aufrecht. Sobald die Map mehr als 2 Einträge enthält, bewegen Sie den linken Zeiger nach rechts, verringern die Häufigkeit und löschen den Eintrag bei null, bis die Bedingung wieder erfüllt ist. Dies ist ein Spezialfall des Problems „höchstens k verschiedene Zeichen“ mit 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')Maximum im Sliding Window
Finden Sie das Maximum in jedem Fenster der Größe k. Eine Brute-Force-Prüfung des Maximums jedes Fensters benötigt O(n×k). Der optimale Ansatz verwendet eine monotone Deque von Indizes: Halten Sie eine absteigend sortierte Deque aufrecht, sodass das vorderste Element immer der Index des aktuellen Fensterm maximums ist. Entfernen Sie Indizes am Anfang, sobald sie das Fenster verlassen, und am Ende, sobald ein größeres Element hinzukommt. Die Gesamtlaufzeit beträgt 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]Wann Sie Sliding Window verwenden sollten
Verwenden Sie Sliding Window, wenn Sie Folgendes sehen:
- Teilstrings oder Teilarrays mit einer Bedingung (maximale Länge, Summe = k, höchstens k verschiedene Zeichen)
- Eine feste Fenstergröße mit einer Aggregation (Maximum, Summe, Häufigkeit)
- Fragen zu zusammenhängenden Bereichen (keine beliebigen Teilmengen)
# 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])) # 2Gültige Fenster zählen: höchstens K
Bei manchen Problemen soll die Anzahl der Teilarrays ermittelt werden, die eine Bedingung erfüllen. Ein nützlicher Trick besteht darin, Teilarrays mit höchstens k verschiedenen Zeichen zu zählen und anschließend die Anzahl mit genau k zu berechnen: exactly(k) = at_most(k) - at_most(k-1). Jeder Aufruf von at_most benötigt O(n), sodass insgesamt O(n) entsteht. Die Funktion at_most zählt Fenster, in denen die Anzahl der verschiedenen Zeichen k nicht überschreitet, indem sie right - left + 1 addiert — die Anzahl aller gültigen linken Endpunkte für jedes rechte Ende.
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)) # 9Kurzer Test
Testen Sie Ihr Verständnis der Konzepte aus Data Structures & Algorithms — Coding Interview Prep, die in dieser Lektion behandelt wurden.
Zusammenfassung der Lektion
In dieser Lektion haben Sie gelernt: Das Sliding Window vermeidet O(n²), indem es einen laufenden Fensterzustand aufrechterhält, der beim Hinzukommen und Entfernen von Elementen in O(1) aktualisiert wird, bei Fenstern fester Größe bewegen sich beide Zeiger im gleichen Tempo weiter; Fenster variabler Größe werden nach rechts gierig erweitert und nur dann nach links verkleinert, wenn eine Bedingung verletzt wird und „kleinstes Teilstring-Fenster“ sowie „Permutation in einem String“ verwenden beide einen Fensterzustand mit Häufigkeitsmap und einen Zähler für die aktuell erfüllten erforderlichen Zeichen. Als Nächstes sehen Sie sich Anagramme und Häufigkeitsmaps für Zeichen an.
Häufig gestellte Fragen
Ist die Lektion „Sliding Window für Teilstrings“ kostenlos?
Ja — der vollständige Text von „Sliding Window für Teilstrings“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Coding Interview Prep-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Coding Interview Prep-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Sliding Window für Teilstrings“?
Implementieren Sie ein Sliding Window variabler Größe, um den längsten Teilstring ohne wiederholte Zeichen und das kleinste Fenster mit allen Zielzeichen zu finden. Du übst Coding Interview Prep mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Coding Interview Prep zu starten?
Keine Vorkenntnisse erforderlich. Coding Interview Prep auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 2 von 4.
Wie lange dauert die Lektion „Sliding Window für Teilstrings“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Coding Interview Prep-Lektion Code schreiben und ausführen?
Ja. Jede Coding Interview Prep-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Python-String-API für Interviews
- Sliding Window für Teilstrings
- Anagramme und Zeichenhäufigkeitskarten
- String-Kodierung, Umkehrung und Palindrome