Software-Engineer-Interviews folgen bei den meisten Unternehmen einem bekannten Muster: ein Anruf vom Recruiter, eine oder zwei Coding-Runden, eine System-Design-Runde für Mid-Level- und Senior-Rollen und eine Verhaltensrunde. Unten findest du 20 Interviewfragen für Software Engineers mit Antworten, nach Runden gruppiert. Jedes Code-Beispiel wurde vor der Veröffentlichung gegen eine Brute-Force-Version mit Tausenden zufälliger Eingaben getestet.
Was jede Runde prüft
| Runde | Üblicher Ablauf | Was bewertet wird |
|---|---|---|
| Recruiter-Screening | 20 bis 30 Minuten am Telefon | Hintergrund, Motivation, Gehaltsspanne, Organisatorisches |
| Coding | 45 bis 60 Minuten in einem gemeinsamen Editor | Problemlösung, sauberer Code, Tests, lautes Denken beim Arbeiten |
| CS-Grundlagen | Eingebettet in das Coding oder eine eigene Runde | Ob du die Systeme verstehst, die du benutzt |
| System Design | 45 bis 60 Minuten am Whiteboard oder in einem Dokument | Abwägungen, Skalierung und klare Kommunikation |
| Verhalten | 30 bis 45 Minuten | Verantwortungsbewusstsein, Zusammenarbeit, Umgang mit Scheitern |
Interviews für Berufseinsteiger bestehen vor allem aus Coding und Verhaltensfragen. Bei Senior-Interviews kommt mehr System Design hinzu, und man erwartet tiefere Antworten zu früheren Projekten. Zum Recruiter-Anruf siehe unsere Fragen im Telefon-Screening.
Coding-Fragen
In jeder Coding-Runde solltest du deinen Ansatz nennen, bevor du tippst, die Zeit- und Speicherkomplexität angeben und am Ende mit einem kleinen Beispiel testen. Unser Big-O-Spickzettel erklärt den Teil zur Komplexität.
1. Two Sum: die Indizes zweier Zahlen zurückgeben, deren Summe das Ziel ergibt
Speichere den Index jeder Zahl in einer Hash-Map. Prüfe bei jeder neuen Zahl, ob ihr Gegenstück bereits in der Map steht.
def two_sum(nums, target):
seen = {}
for i, x in enumerate(nums):
if target - x in seen:
return [seen[target - x], i]
seen[x] = i
return []
print(two_sum([2, 7, 11, 15], 9)) # [0, 1]
O(n) Zeit und O(n) Speicher. Die Brute-Force-Variante prüft jedes Paar in O(n²), und Interviewer wollen meist, dass du sie zuerst erwähnst und dann verbesserst.
2. Gültige Klammern: prüfen, ob jede Klammer in der richtigen Reihenfolge geschlossen wird
Lege öffnende Klammern auf einen Stack. Bei einer schließenden Klammer muss das oberste Element des Stacks die passende öffnende Klammer sein.
def is_valid(s):
pairs = {")": "(", "]": "[", "}": "{"}
stack = []
for ch in s:
if ch in pairs:
if not stack or stack.pop() != pairs[ch]:
return False
else:
stack.append(ch)
return not stack
print(is_valid("([]{})"), is_valid("(]")) # True False
O(n) Zeit und O(n) Speicher. Die letzte Zeile ist wichtig: Ein String wie "((" lässt Elemente auf dem Stack zurück und ist nicht gültig.
3. Überlappende Intervalle zusammenführen
Sortiere nach Startzeit und erweitere dann entweder das zuletzt zusammengeführte Intervall oder beginne ein neues.
def merge_intervals(intervals):
merged = []
for start, end in sorted(intervals):
if merged and start <= merged[-1][1]:
merged[-1][1] = max(merged[-1][1], end)
else:
merged.append([start, end])
return merged
print(merge_intervals([[1, 3], [2, 6], [8, 10], [15, 18]]))
# [[1, 6], [8, 10], [15, 18]]
O(n log n) Zeit wegen des Sortierens. Frag nach, ob sich aneinandergrenzende Intervalle wie [1, 2] und [2, 3] zusammenführen sollen. Diese Version führt sie zusammen.
4. Eine verkettete Liste umkehren
Gehe die Liste einmal durch und zeige bei jedem Knoten auf den vorherigen.
class ListNode:
def __init__(self, val, next=None):
self.val = val
self.next = next
def reverse_list(head):
prev = None
while head:
head.next, prev, head = prev, head, head.next
return prev
O(n) Zeit und O(1) zusätzlicher Speicher. Wenn dem Interviewer die Mehrfachzuweisung zu raffiniert erscheint, schreib sie als drei Zeilen mit einer temporären Variablen. Klar ist besser als kurz.
5. Die k häufigsten Elemente zurückgeben
Zähle mit einer Hash-Map und nimm dann mit einem Heap die k größten Zählwerte.
from collections import Counter
import heapq
def top_k_frequent(nums, k):
counts = Counter(nums)
return [x for x, _ in heapq.nlargest(k, counts.items(), key=lambda p: p[1])]
print(top_k_frequent([1, 1, 1, 2, 2, 3], 2)) # [1, 2]
O(n log k) Zeit. Eine Nachfrage ist die Bucket-Sortierung nach Häufigkeit, die O(n) erreicht.
6. Einen LRU-Cache mit O(1) für get und put entwerfen
Du brauchst schnelles Nachschlagen und schnelles Umsortieren nach der letzten Nutzung. Eine Hash-Map plus eine doppelt verkettete Liste leisten beides. In Python ist OrderedDict genau diese Kombination.
from collections import OrderedDict
class LRUCache:
def __init__(self, capacity):
self.capacity = capacity
self.data = OrderedDict()
def get(self, key):
if key not in self.data:
return -1
self.data.move_to_end(key)
return self.data[key]
def put(self, key, value):
if key in self.data:
self.data.move_to_end(key)
self.data[key] = value
if len(self.data) > self.capacity:
self.data.popitem(last=False)
Manche Interviewer bitten dich, die verkettete Liste selbst zu bauen. Erkläre zuerst den Aufbau: Die Map zeigt auf Listenknoten, der neueste Knoten sitzt an einem Ende, und du verdrängst vom anderen Ende.
7. Kürzester Weg in einem Raster mit Wänden
Die Breitensuche findet den kürzesten Weg, wenn jeder Schritt gleich viel kostet.
from collections import deque
def shortest_path(grid):
rows, cols = len(grid), len(grid[0])
if grid[0][0] or grid[rows - 1][cols - 1]:
return -1
queue = deque([(0, 0, 0)])
seen = {(0, 0)}
while queue:
r, c, steps = queue.popleft()
if (r, c) == (rows - 1, cols - 1):
return steps
for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)):
nr, nc = r + dr, c + dc
if 0 <= nr < rows and 0 <= nc < cols and not grid[nr][nc] and (nr, nc) not in seen:
seen.add((nr, nc))
queue.append((nr, nc, steps + 1))
return -1
print(shortest_path([[0, 0, 0], [1, 1, 0], [0, 0, 0]])) # 4
O(Zeilen × Spalten) Zeit und Speicher. Markiere Zellen als besucht, wenn du sie in die Warteschlange legst, nicht wenn du sie herausnimmst, sonst wird dieselbe Zelle viele Male eingereiht.
8. Die erste fehlerhafte Version finden
Die Versionen 1 bis n sind bis zu einem bestimmten Punkt gut und ab da fehlerhaft. Die binäre Suche findet die erste fehlerhafte Version mit O(log n) Prüfungen.
def first_bad_version(n, is_bad):
lo, hi = 1, n
while lo < hi:
mid = (lo + hi) // 2
if is_bad(mid):
hi = mid
else:
lo = mid + 1
return lo
Das Muster passt auf jede Ja-oder-Nein-Frage, die sich genau einmal umdreht, und das kommt oft vor. Eine Liste mit Aufgaben, die diese Muster abdecken, findest du im Blind 75.
Fragen zu den CS-Grundlagen
9. Was ist der Unterschied zwischen einem Prozess und einem Thread?
Ein Prozess ist ein laufendes Programm mit eigenem Speicherbereich. Threads laufen innerhalb eines Prozesses und teilen sich dessen Speicher. Threads sind günstiger zu erzeugen und umzuschalten und können Daten direkt teilen, aber genau dieses Teilen ist der Grund für Sperren und Race Conditions. Prozesse sind voneinander isoliert, daher reißt der Absturz eines Prozesses die anderen nicht mit.
10. Was ist der Unterschied zwischen TCP und UDP?
TCP baut eine Verbindung auf und garantiert eine geordnete, zuverlässige Zustellung mit erneuter Übertragung und Flusskontrolle. UDP sendet unabhängige Pakete ohne Garantie für Zustellung oder Reihenfolge und hat weniger Overhead. Nutze TCP für Webseiten, APIs und Dateiübertragung. UDP eignet sich für Live-Sprache, Video und Spiele, wo ein verspätetes Paket ohnehin nichts mehr nützt. Unsere Fragen zu Computernetzwerken im Interview gehen weiter in die Tiefe.
11. Was passiert, wenn du eine URL in den Browser eingibst und Enter drückst?
Der Browser löst den Domainnamen über DNS in eine IP-Adresse auf, öffnet eine TCP-Verbindung und führt bei HTTPS einen TLS-Handshake durch. Er sendet eine HTTP-Anfrage, und der Server, oft hinter einem Load Balancer, schickt eine Antwort zurück. Der Browser parst das HTML, lädt das CSS, das JavaScript und die Bilder, auf die verwiesen wird, und rendert die Seite. Geh in die Tiefe bei dem Teil, den der Interviewer auswählt.
12. Wie funktioniert eine Hash-Tabelle, und wie hoch ist ihre Zeitkomplexität?
Eine Hash-Funktion ordnet jeden Schlüssel einem Bucket in einem Array zu. Suchen, Einfügen und Löschen sind im Durchschnitt O(1). Wenn zwei Schlüssel im selben Bucket landen, löst die Tabelle die Kollision durch Verkettung oder durch Sondierung eines anderen Platzes, und sie wächst, wenn sie zu voll wird. Im schlechtesten Fall ist es O(n), wenn viele Schlüssel kollidieren.
13. Wann würdest du eine SQL-Datenbank statt einer NoSQL-Datenbank wählen?
Wähle SQL, wenn die Daten relational sind, du Joins und Transaktionen brauchst und das Schema ziemlich stabil ist: Bestellungen, Zahlungen, Benutzerkonten. Wähle einen Dokument- oder Key-Value-Speicher, wenn die Zugriffsmuster einfach sind, die Datenstruktur variiert oder du Schreibvorgänge auf viele Rechner verteilen musst. Viele Systeme nutzen beides. Die Antwort, die Interviewer hören wollen, ist der Kompromiss, nicht ein Sieger. Unsere REST-API-Fragen im Interview behandeln die API-Schicht, die meist darüber liegt.
Fragen zu System Design
14. Entwirf einen URL-Shortener
Kläre zuerst die Anforderungen: wie viele neue Links pro Tag, wie viele Aufrufe, ob Links ablaufen, ob eigene Aliase erlaubt sind. Dann behandelst du die API (Erstellen und Weiterleiten), wie du Kurzcodes erzeugst (ein Zähler in Base 62 kodiert oder ein zufälliger Code mit Eindeutigkeitsprüfung), die Speicherung (ein Key-Value-Speicher von Code zu URL) und einen Cache für beliebte Links, da Lesezugriffe die Schreibzugriffe weit übertreffen. Zum Schluss kommen, wenn Zeit bleibt, Analysen und der Schutz vor Missbrauch. Den gesamten Entwurf gehen wir in unserem Leitfaden zu System Design durch.
15. Entwirf einen Rate Limiter
Beginne damit, wo er läuft (am API-Gateway, pro Nutzer oder pro API-Schlüssel) und was passiert, wenn ein Client das Limit überschreitet (HTTP 429 mit einer Wartezeit). Ein Token-Bucket-Verfahren ist die übliche Wahl: Jeder Client hat einen Behälter, der mit fester Rate nachgefüllt wird und eine maximale Anzahl an Tokens fasst, und jede Anfrage verbraucht einen. Er erlaubt kurze Spitzen und setzt dennoch eine durchschnittliche Rate durch. Bei mehreren Servern hältst du die Zähler in einem gemeinsamen Speicher wie Redis, damit jeder Server denselben Stand sieht. Für mehr Übung siehe unsere Fragen zu System Design im Interview.
Verhaltensfragen
Verwende für jede Geschichte eine klare Struktur: die Situation, was du getan hast und das Ergebnis, mit Zahlen, wo du sie hast.
16. Erzähl mir etwas über dich
Gib eine zweiminütige Version deines beruflichen Werdegangs, die damit endet, warum du diese Stelle willst. Nenne ein oder zwei Projekte mit konkreten Ergebnissen. Unser Leitfaden Erzähl etwas über dich enthält Beispiele.
17. Erzähl von einem schwierigen Bug, den du behoben hast
Beispielantwort: „Unser Checkout-Service lief ein paar Mal am Tag ohne erkennbares Muster in Timeouts. Ich habe Request-IDs in die Logs aufgenommen und festgestellt, dass alle Timeouts von einer einzigen Datenbankabfrage kamen, die nur lief, wenn ein Warenkorb mehr als 50 Artikel hatte. Der Abfrage fehlte ein Index auf der Join-Spalte. Ich habe den Index ergänzt, die langsame Abfrage ging von etwa 4 Sekunden auf unter 50 Millisekunden zurück, und ich habe einen Alarm auf die Latenz dieser Abfrage eingerichtet, damit wir es beim nächsten Mal früher bemerken.“
18. Erzähl von einem Konflikt mit einem Teamkollegen
Beispielantwort: „Ein Kollege wollte unseren Benachrichtigungsdienst in einem neuen Framework neu schreiben, und ich hielt das Risiko vor einem Launch für zu hoch. Statt in der Besprechung zu streiten, schlug ich vor, dass wir beide Kosten und Risiken aufschreiben. Wir einigten uns darauf, die zwei schlimmsten Probleme im bestehenden Code vor dem Launch zu beheben und die Neuschreibung für das nächste Quartal zu planen. Der Launch ging pünktlich raus, und zwei Monate später haben wir die Neuschreibung mit einem ordentlichen Testplan umgesetzt.“
19. Erzähl von einem Projekt, das gescheitert ist
Wähle ein echtes Scheitern, an dem du einen Teil verantwortlich warst. Erkläre, was schiefging, was du anders machen würdest und was du danach geändert hast. Interviewer achten auf Ehrlichkeit und Lernbereitschaft, nicht auf eine makellose Bilanz.
20. Warum willst du hier arbeiten?
Verbinde etwas Konkretes am Produkt oder an der Engineering-Arbeit des Unternehmens mit deiner eigenen Erfahrung. „Ich nutze eure API seit zwei Jahren und würde gern auf der Plattform-Seite arbeiten“ ist besser als „Ihr seid ein tolles Unternehmen“.
Fragen, die du dem Interviewer stellen kannst
- Wie sieht eine typische Woche für jemanden in diesem Team aus?
- Wie wird die Arbeit geplant, und wer legt die Prioritäten fest?
- Wie laufen Code-Reviews und Deployments hier ab?
- Woran würde man in den ersten sechs Monaten Erfolg erkennen?
- Was ist das schwierigste technische Problem, an dem das Team gerade arbeitet?
Mehr dazu findest du unter Fragen, die du am Ende eines Interviews stellen solltest.
So bereitest du dich vor
- Wähle eine Sprache und verwende sie für jede Übungsaufgabe. Python ist die häufigste Wahl, weil der Code kurz ist. Unsere Python-Fragen im Interview behandeln die Sprache selbst.
- Übe nach Mustern, nicht nach Anzahl: Hash-Maps, zwei Zeiger, gleitendes Fenster, binäre Suche, BFS und DFS, Heaps und dynamische Programmierung.
- Löse Aufgaben laut mit einem Timer. Eine korrekte, aber stille Lösung bewertet man niedriger als eine klare, laut erklärte.
- Übe im Editor, den du auch benutzen wirst. Viele Unternehmen nutzen CoderPad, das eine kostenlose Sandbox hat.
- Bereite fünf Geschichten aus deiner Arbeit vor, die du an die meisten Verhaltensfragen anpassen kannst.
- Für Mid-Level- und Senior-Rollen mach mindestens ein paar vollständige System-Design-Übungen mit jemandem, der Nachfragen stellt.
Coding-Interviews laut üben
YesToTheOffer transkribiert deine Antworten, damit du sehen kannst, wie du deine Lösung erklärt hast, mit Coding-Hilfe aus Screenshots bei 0.2x. 30 kostenlose Minuten, kein Abo.



