Solution
from collections import deque, defaultdict
def find_exit(api: dict) -> str:
# Track remaining transient failures per path, initialized lazily from api
left_500 = defaultdict(int)
left_timeout = defaultdict(int)
def attempt_get(path: str):
node = api.get(path)
if node is None:
# Unknown path: treat as a page with no outgoing links
return ("ok", {"next_step": []})
if node == "Congrats":
return ("ok", "Congrats")
if isinstance(node, dict):
# Initialize counters lazily so they persist across retries
if path not in left_500:
left_500[path] = int(node.get("fail_500", 0) or 0)
if path not in left_timeout:
left_timeout[path] = int(node.get("timeout", 0) or 0)
if left_500[path] > 0:
left_500[path] -= 1
return ("500", None)
if left_timeout[path] > 0:
left_timeout[path] -= 1
return ("timeout", None)
return ("ok", node)
# Malformed entry: treat as page with no outgoing links
return ("ok", {"next_step": []})
q = deque(["/"])
visited = set()
while q:
path = q.popleft()
if path in visited:
continue
status, data = attempt_get(path)
if status != "ok":
# Transient failure: retry later
q.append(path)
continue
if data == "Congrats":
return path.lstrip("/")
# Expand neighbors
steps = data.get("next_step", []) if isinstance(data, dict) else []
if isinstance(steps, list):
for s in steps:
if not isinstance(s, str):
continue
np = s if s.startswith("/") else "/" + s
if np not in visited:
q.append(np)
visited.add(path)
return ""
Explanation
Use BFS starting at "/". Maintain a visited set, but only mark a node visited after a successful fetch to prevent cycles while still allowing retries. For each path, lazily track remaining HTTP 500 and timeout attempts; on such events, re-enqueue the path and proceed with other work. Once a fetch succeeds, either return immediately if it is an exit ("Congrats") or enqueue its neighbors. This guarantees eventual completion when a path exists because each path has finite transient failures.
Time complexity: O(V + E + R), where V is the number of reachable paths, E is the total number of next_step edges explored, and R is the total count of transient errors/timeouts across reachable paths.. Space complexity: O(V).