← Block (Square) Interview Insights

Block (Square)·Data Scientist·Technical Phone Screen·Senior

Senior
Jun 2026

Summary

Block (Square) data scientist technical screen, basically one long coding problem about graph traversal on a referral dataset. The question had a lot of moving parts and I'm still not sure I nailed the complexity justification.

Questions Asked (5)

Q1

Given a directed referral graph loaded from a CSV (up to 1 million users, nullable referred_by, possible duplicates and cycles), implement a function that returns the referral chain from the earliest ancestor down to a given user. If a cycle is detected on the path, return both the cycle nodes in encounter order and the acyclic prefix leading into it.

Algorithms & Data StructuresTechnical Trade-offs
Author's notes

This was the core of the whole interview.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Clarify the input format and edge cases (nullable referred_by, duplicates, cycles) before designing the solution. Propose a hash map from user to referrer for O(1) lookups, then traverse upward from the given user while tracking visited nodes to detect cycles. If a cycle is found, return the acyclic prefix and the cycle nodes in encounter order; otherwise, reverse the path to get the chain from the earliest ancestor.

Pro tip: Emphasize that you would validate the graph structure early (e.g., check for self-referrals or duplicate edges) and discuss how you'd handle memory constraints for 1M users, such as using a compact data structure or streaming the CSV.

1. Clarify requirements and edge cases

Ask about the CSV schema, whether referred_by can be null, how duplicates should be handled, and the expected output format for cycles. Confirm that the referral chain should be ordered from earliest ancestor to the given user.

2. Choose data structures and algorithm

Propose using a hash map (dictionary) to store each user's referrer for O(1) lookups. Plan to traverse upward from the given user, maintaining a list of visited nodes and a set for cycle detection.

3. Handle cycles and build the chain

During traversal, if a node repeats, identify the cycle nodes in encounter order and the acyclic prefix. Otherwise, collect the path and reverse it to get the chain from the earliest ancestor.

4. Address scalability and data quality

Discuss memory usage for 1M users (e.g., using arrays or compact structures), and how to handle duplicates (e.g., last-write-wins or validate consistency). Mention time complexity O(n) for traversal.

5. Test and validate

Walk through test cases: normal chain, cycle, null referrer, duplicate entries, and large input. Explain how you'd verify correctness and performance.

Key Points to Mention

  • Use a hash map for O(1) referrer lookups, ensuring efficient traversal.
  • Cycle detection using a visited set or two-pointer technique (Floyd's algorithm) for O(1) space.
  • Handling nullable referred_by: treat as root (no referrer).
  • Duplicate entries: decide on a policy (e.g., last occurrence wins) and mention data validation.
  • Output format: for cycles, return acyclic prefix and cycle nodes in encounter order; otherwise, return full chain from root to user.
  • Scalability: consider memory footprint for 1M users and potential streaming or batch processing.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

Compute root_ancestor and chain_depth for every user in O(n) time and O(n) space without recomputing paths from scratch for each user. Justify your complexity.

Algorithms & Data StructuresSystem Design
Author's notes

The justification part is where I fumbled.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Model the user hierarchy as a tree and perform a single post-order traversal to compute root_ancestor and chain_depth for all nodes. Use memoization to avoid recomputing paths, ensuring O(n) time and space. Justify by noting each node is visited once and stored once.

Pro tip: Explicitly discuss handling of edge cases like cycles, multiple roots, or disconnected components, and mention that the solution scales to large datasets by avoiding recursion depth issues with an iterative approach.

1. Clarify the problem and assumptions

Confirm the definition of root_ancestor and chain_depth, and whether the hierarchy is a tree (single root, no cycles). Ask about input format and constraints.

2. Choose the right data structure and traversal

Represent the hierarchy as an adjacency list or parent pointers. Use post-order DFS (iterative to avoid stack overflow) to compute values bottom-up.

3. Define recurrence relations

For each node, root_ancestor is the root of its subtree (or itself if root), and chain_depth is 1 + max child chain_depth. Compute these during traversal.

4. Implement with memoization

Store computed values in a hash map or array to reuse for parent computations. Ensure each node is processed exactly once.

5. Analyze complexity and edge cases

Argue O(n) time because each node is visited once and O(n) space for storage. Discuss handling of cycles, multiple roots, or missing parents.

Key Points to Mention

  • Tree traversal (post-order DFS) to compute values bottom-up
  • Memoization to avoid recomputing paths for each user
  • Time complexity O(n) because each node is visited once
  • Space complexity O(n) for storing results and recursion/stack
  • Handling of edge cases: cycles, multiple roots, disconnected components
  • Iterative implementation to avoid recursion depth limits

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q3

Return the top 3 longest valid acyclic chains, with ties broken first by smaller root ancestor ID and then lexicographically by the full chain list.

Algorithms & Data Structures
Author's notes

Honestly the tie-breaking rule caught me off guard.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Clarify the definition of a valid acyclic chain and the input graph structure, then propose an algorithm that finds all maximal chains, filters for acyclic ones, and sorts them by length descending, root ancestor ID ascending, and lexicographic order of the chain list. Discuss time and space complexity, and consider optimizations like memoization or topological sorting if the graph is a DAG.

Pro tip: Always confirm edge cases with the interviewer, such as empty graph, multiple components, or chains of equal length and root ID, to show thoroughness. Also, mention that you would validate the acyclic property using cycle detection (e.g., DFS with recursion stack) before processing.

1. Clarify requirements and constraints

Ask about the graph representation (adjacency list/matrix), whether it's directed/undirected, and the exact definition of a 'valid acyclic chain' (e.g., simple path with no repeated nodes). Confirm tie-breaking rules and output format.

2. Design algorithm to enumerate chains

Use DFS from each node to explore all simple paths, pruning when a cycle is detected (e.g., node already in current path). Alternatively, if the graph is a DAG, use topological order and DP to find longest paths from each root.

3. Filter and sort chains

Collect all valid chains, then sort them by length descending, root ancestor ID ascending, and finally lexicographically by the sequence of node IDs. Select the top 3.

4. Analyze complexity and optimize

Discuss worst-case time complexity (exponential for general graphs) and suggest optimizations like memoization for DAGs or early termination if only top 3 are needed. Mention space complexity.

5. Test with examples and edge cases

Walk through a small example to verify correctness, including ties and cycles. Consider edge cases: empty graph, single node, disconnected components, and chains with same length and root.

Key Points to Mention

  • Definition of a valid acyclic chain (simple path with no repeated vertices)
  • Cycle detection using DFS with recursion stack or visited set
  • Sorting criteria: length descending, root ancestor ID ascending, lexicographic order of chain list
  • Time and space complexity analysis, including worst-case exponential for general graphs
  • Optimization techniques: memoization for DAGs, topological sorting, or pruning
  • Handling edge cases: empty graph, multiple components, ties in length and root ID

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q4

Describe and implement preprocessing for the CSV input: deduplicate rows keeping the earliest seen parent when conflicts exist, normalize null or empty referred_by values, handle referred_by values not present in the user list by treating them as external roots, and flag self-referrals.

Data ModelingTechnical Trade-offs
Author's notes

This felt like the 'real world' part of the question and I actually liked it.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the data schema and business rules (e.g., what defines a duplicate, how to determine 'earliest seen', and what constitutes a self-referral). Then outline a step-by-step preprocessing pipeline that handles each requirement in a logical order, ensuring data integrity and explainability. Finally, discuss trade-offs and edge cases, such as performance implications and how to validate the output.

Pro tip: Emphasize the importance of documenting assumptions and validating the preprocessing with unit tests or sample data, as this demonstrates production-ready thinking and reduces downstream errors.

1. Clarify requirements and data schema

Ask questions to understand the CSV structure, what 'earliest seen' means (e.g., timestamp or row order), and how null/empty values are represented. Confirm the definition of a self-referral and external roots.

2. Deduplicate rows with conflict resolution

Identify duplicate rows based on a key (e.g., user ID). When conflicts exist in the parent field, keep the parent from the earliest seen record, using a timestamp or original row order.

3. Normalize referred_by values

Standardize null or empty referred_by values to a consistent representation (e.g., None or a sentinel value) to simplify downstream logic.

4. Handle external roots and flag self-referrals

For referred_by values not in the user list, treat them as external roots (e.g., mark as 'external'). For rows where referred_by equals the user ID, flag them as self-referrals (e.g., add a boolean column).

5. Validate and document the pipeline

Test the preprocessing with edge cases (e.g., all nulls, all self-referrals) and document assumptions and transformations for reproducibility.

Key Points to Mention

  • Definition of 'earliest seen' and how to determine it (timestamp vs. row order)
  • Handling of null/empty values: normalization strategy and sentinel value choice
  • Treatment of external roots: how to identify and represent them (e.g., separate column or placeholder)
  • Self-referral detection: logic and flagging mechanism
  • Trade-offs: performance vs. accuracy, memory usage for large datasets
  • Validation: unit tests, sample data, and logging for auditability

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q5

Write minimal unit tests covering an acyclic chain, a self-cycle, and a two-node cycle using the provided example rows.

Algorithms & Data Structures
Author's notes

They gave the exact expected behaviors so this was more about writing clean assertions than figuring out the logic.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First, clarify the function under test and the input format (e.g., a list of edges or a mapping). Then, design three minimal test cases: one acyclic chain, one self-cycle, and one two-node cycle, using the provided example rows to construct the inputs and expected outputs. Write concise unit tests that assert the correct cycle detection behavior for each case.

Pro tip: Mention that you would also test edge cases like empty input or a single node without a self-loop, and that you keep tests minimal but meaningful to avoid overfitting to the example.

1. Understand the function and input

Identify what the function does (e.g., detect cycles in a directed graph) and how the input is structured (e.g., list of edges, adjacency list). Confirm the expected output format (e.g., boolean, list of cycles).

2. Design the acyclic chain test

Create a simple chain like A→B→C with no cycles. Assert that the function returns False or an empty list, depending on the output contract.

3. Design the self-cycle test

Create a single node with a self-loop (e.g., A→A). Assert that the function correctly identifies a cycle.

4. Design the two-node cycle test

Create a cycle between two nodes (e.g., A→B→A). Assert that the function detects the cycle.

5. Write and organize the tests

Use a testing framework (e.g., pytest, unittest) to write three separate test functions. Keep each test minimal and focused on one scenario, using the provided example rows to construct inputs.

Key Points to Mention

  • Clarify the function signature and expected output before writing tests.
  • Use the provided example rows to construct realistic inputs.
  • Ensure each test is independent and tests only one scenario.
  • Include assertions that check both positive and negative cases.
  • Consider edge cases like empty input or disconnected components.
  • Keep tests minimal but sufficient to cover the required scenarios.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.