Level: Unknown Level
Round: Full Journey · Type: Coding · Difficulty: 7/10 · Duration: 180 min · Interviewer: Unfriendly
Topics: Binary Search, Breadth-First Search, Depth-First Search, Graphs, Debugging
Location: San Francisco Bay Area
Interview date: 2026-01-08
Question: Find the first error log in a list of logs using binary search, given that once an error appears, all subsequent logs are also errors.
Question: Given a list of service calls and a first error service, find all services that will fail using BFS or DFS.
Question: Building on Part 2, find the longest path of errors starting from the first error service using DFS.
The interview focused on debugging service failures and was divided into three parts.
Part 1: Finding the First Error (Binary Search)
The challenge was to find the index of the first error log in a list of strings, where each line begins with '[Info]', '[Warn]', or '[Error]'. After the first '[Error]' appears, every subsequent log line is also an '[Error]'. The line before an error must be a '[Warn]'. If there are no errors, return -1. I used binary search to solve this problem. Here is the code:
` def is_error(log_line: str) -> bool: return log_line.startswith("[Error]")
def first_error_index(logs: list[str]) -> int: left = 0 right = len(logs) - 1 answer = -1
while left <= right:
mid = (left + right) // 2
if is_error(logs[mid]):
answer = mid
right = mid - 1
else:
left = mid + 1
return answer
`
Part 2: Finding All Affected Services (Graph BFS/DFS)
I was given a dictionary showing which service calls which:
calls = { "A": ["B", "C"], # A calls B and C "B": ["D"], "C": ["D"], "E": ["A"], "F": ["C"], }
The rule is that if a service crashes, any service that relies on it (directly or indirectly) will also fail. Given the name of the first_error_service, I needed to return a set of all services that will eventually fail. I used Breadth-First Search (BFS) to solve this problem. Here is the code:
` from collections import defaultdict, deque
def impacted_services( calls: dict[str, list[str]], first_error_service: str, ) -> set[str]: # Build reverse graph: callee -> list of callers reverse_graph: dict[str, list[str]] = defaultdict(list) for caller, callees in calls.items(): for callee in callees: reverse_graph[callee].append(caller)
impacted: set[str] = {first_error_service}
q = deque([first_error_service])
while q:
service = q.popleft()
for caller in reverse_graph.get(service, []):
if caller in impacted:
continue
impacted.add(caller)
q.append(caller)
return impacted
`
Part 3: Finding the Longest Chain of Errors (DFS)
Building on Part 2, I had to find one longest path of errors starting from the first_error_service. I used Depth-First Search (DFS) on the reverse graph. Here is the code:
` from collections import defaultdict
def longest_error_chain( calls: dict[str, list[str]], first_error_service: str, ) -> list[str]: # Build reverse graph reverse_graph: dict[str, list[str]] = defaultdict(list) for caller, callees in calls.items(): for callee in callees: reverse_graph[callee].append(caller)
memo: dict[str, list[str]] = {}
state: dict[str, int] = {} # 0/absent=unseen, 1=visiting, 2=done
def dfs(service: str) -> list[str]:
# Check for cycles
if state.get(service, 0) == 1:
raise ValueError("Cycle detected: longest simple path in general graph is non-trivial.")
# Return cached result if available
if state.get(service, 0) == 2:
return memo[service]
state[service] = 1
best_chain = [service]
# Try all upstream callers to find the longest path
for caller in reverse_graph.get(service, []):
candidate = [service] + dfs(caller)
if len(candidate) > len(best_chain):
best_chain = candidate
state[service] = 2
memo[service] = best_chain
return best_chain
return dfs(first_error_service)
`