PracHub
QuestionsPremiumCoachesLearningGuidesInterview Prep

Quick Overview

This question evaluates understanding of graph algorithms and pathfinding, covering tree diameter computation and grid shortest-path problems as well as enumeration of simple paths, and requires skills in traversal techniques, combinatorial reasoning, and time/space complexity analysis.

  • medium
  • Meta
  • Coding & Algorithms
  • Software Engineer

Solve tree diameter and grid path problems

Company: Meta

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Technical Screen

You are interviewing for a software engineer / ML intern role and are given the following algorithmic problems. --- ### Question 1: Longest Path in a Tree You are given a **tree**, i.e., a connected, undirected, acyclic graph with \(n\) nodes labeled from 1 to \(n\), and \(n - 1\) edges. Each edge is unweighted (or equivalently has weight 1). **Task:** Find the **length of the longest path** between any two nodes in the tree. The length of a path is defined as the number of edges on that path. - **Input:** - An integer \(n\), the number of nodes. - A list of \(n - 1\) edges, each edge given as a pair \((u, v)\) indicating an undirected edge between nodes \(u\) and \(v\). - **Output:** - A single integer: the maximum number of edges on any simple path between two nodes in the tree. You should describe an algorithm (no need to provide code) and analyze its time and space complexity. Assume \(1 \le n \le 10^5\), so the algorithm must be close to linear time. --- ### Question 2: Shortest Path in an Obstacle Grid (and All Paths) You are given an \(n \times n\) grid representing a 2D map. Each cell is either **free** or **blocked**: - `0` means the cell is free. - `1` means the cell is blocked (an obstacle) and cannot be stepped on. You start in the **top-left** cell `(0, 0)` and want to reach the **bottom-right** cell `(n - 1, n - 1)`. From any cell, you may move **one step at a time** in the four cardinal directions: - Up: `(r - 1, c)` - Down: `(r + 1, c)` - Left: `(r, c - 1)` - Right: `(r, c + 1)` You may only move to cells that are within bounds and free (`0`). #### Part A: Shortest Path Length **Task:** Find the **length (in number of steps)** of the shortest path from `(0, 0)` to `(n - 1, n - 1)`. - If there is no valid path, return `-1`. - **Input:** - An integer \(n\) (e.g., up to a few hundred). - An \(n \times n\) matrix `grid` of 0s and 1s. - **Output:** - A single integer: the minimum number of steps needed to reach `(n - 1, n - 1)` from `(0, 0)`, or `-1` if impossible. Describe the algorithm you would use and analyze its time and space complexity. #### Part B (Follow-up): Enumerate All Paths Now, suppose we want to **find all possible paths** from `(0, 0)` to `(n - 1, n - 1)` under the same movement and obstacle rules. 1. Describe an approach to **enumerate all distinct simple paths** (paths that do not revisit any cell). 2. Discuss: - How you would represent each path in memory. - The time and space complexity in terms of \(n\) and the number of valid paths \(K\). - Any practical limitations when \(n\) is moderately large and/or when there may be exponentially many paths. You may assume \(n\) is small enough that, in principle, all paths could be generated for the sizes considered (e.g., in a whiteboard or interview setting), but you should still comment on scalability and limitations.

Quick Answer: This question evaluates understanding of graph algorithms and pathfinding, covering tree diameter computation and grid shortest-path problems as well as enumeration of simple paths, and requires skills in traversal techniques, combinatorial reasoning, and time/space complexity analysis.

Longest Path in a Tree (Tree Diameter)

You are given a tree: a connected, undirected, acyclic graph with `n` nodes labeled from `1` to `n` and `n - 1` unweighted edges. Find the length of the longest path between any two nodes, where the length of a path is the number of edges on it (this is the tree's diameter). Implement `solution(n, edges)` where `n` is the node count and `edges` is a list of `(u, v)` pairs. Return a single integer: the maximum number of edges on any simple path. Classic two-BFS approach: from any node, BFS to find the farthest node `a`; then BFS from `a` to find the farthest distance — that distance is the diameter. Runs in O(n) time and O(n) space, which satisfies the n up to 1e5 constraint.

Constraints

  • 1 <= n <= 10^5
  • edges has exactly n - 1 pairs
  • The graph is guaranteed to be a tree (connected and acyclic)
  • Nodes are labeled from 1 to n
  • Return 0 for a single-node tree (no edges)

Examples

Input: (1, [])

Expected Output: 0

Explanation: A single node has no edges, so the longest path has length 0.

Input: (2, [(1, 2)])

Expected Output: 1

Explanation: The only path uses 1 edge between nodes 1 and 2.

Input: (4, [(1, 2), (2, 3), (2, 4)])

Expected Output: 2

Explanation: Longest path is 1-2-3 (or 3-2-4 / 1-2-4), all with 2 edges.

Input: (6, [(1, 2), (1, 3), (3, 4), (3, 5), (5, 6)])

Expected Output: 4

Explanation: Longest path is 2-1-3-5-6 with 4 edges.

Input: (7, [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)])

Expected Output: 6

Explanation: A straight chain of 7 nodes has a diameter of 6 edges.

Input: (5, [(1, 2), (1, 3), (1, 4), (1, 5)])

Expected Output: 2

Explanation: A star: any leaf-to-leaf path passes through the center, using 2 edges.

Solution

from collections import defaultdict, deque

def solution(n, edges):
    if n <= 1:
        return 0
    adj = defaultdict(list)
    for u, v in edges:
        adj[u].append(v)
        adj[v].append(u)

    def bfs(start):
        visited = {start}
        q = deque([(start, 0)])
        far_node, far_dist = start, 0
        while q:
            node, dist = q.popleft()
            if dist > far_dist:
                far_dist, far_node = dist, node
            for nxt in adj[node]:
                if nxt not in visited:
                    visited.add(nxt)
                    q.append((nxt, dist + 1))
        return far_node, far_dist

    a, _ = bfs(1)
    _, diameter = bfs(a)
    return diameter

Time complexity: O(n) — two BFS traversals over a tree with n nodes and n-1 edges.. Space complexity: O(n) — adjacency list, visited set, and BFS queue..

Hints

  1. The diameter is the longest shortest-path between any two nodes. Brute-forcing all pairs is O(n^2) — too slow for n up to 1e5.
  2. Key lemma: from ANY node, the farthest node found by BFS/DFS is guaranteed to be one endpoint of a diameter.
  3. Run BFS twice: first from node 1 to find a farthest node `a`, then from `a` to find the farthest distance. That distance is the diameter.
  4. Each BFS is O(n) on a tree, so the total is linear.

Shortest Path in an Obstacle Grid (BFS)

You are given an `n x n` grid where `0` is a free cell and `1` is a blocked cell (obstacle). Starting at the top-left `(0, 0)`, find the minimum number of steps to reach the bottom-right `(n - 1, n - 1)`, moving one cell at a time in the four cardinal directions (up, down, left, right) onto in-bounds free cells only. Return `-1` if no valid path exists. Implement `solution(grid)` returning the shortest step count, or `-1`. Because every move costs the same, breadth-first search from the start expands cells in increasing distance order, so the first time you dequeue the destination you have the shortest path. Time and space are O(n^2).

Constraints

  • 1 <= n (grid is square, n x n)
  • Each cell is 0 (free) or 1 (blocked)
  • Movement is restricted to the four cardinal directions
  • Return -1 if the start or end is blocked, or no path exists
  • Steps count edges traversed; a 1x1 free grid returns 0

Examples

Input: ([[0]],)

Expected Output: 0

Explanation: Start equals the destination, so zero steps are needed.

Input: ([[0, 0], [0, 0]],)

Expected Output: 2

Explanation: Go right then down (or down then right): 2 steps to (1,1).

Input: ([[0, 1], [1, 0]],)

Expected Output: -1

Explanation: Both neighbors of the start are blocked, so the destination is unreachable.

Input: ([[0, 0, 0], [1, 1, 0], [0, 0, 0]],)

Expected Output: 4

Explanation: Path (0,0)->(0,1)->(0,2)->(1,2)->(2,2) uses 4 steps.

Input: ([[1, 0], [0, 0]],)

Expected Output: -1

Explanation: The start cell itself is blocked, so no path can begin.

Input: ([[0, 0, 0], [0, 1, 0], [0, 0, 0]],)

Expected Output: 4

Explanation: The center obstacle forces a route around it, but the Manhattan distance of 4 is still achievable.

Solution

from collections import deque

def solution(grid):
    n = len(grid)
    if n == 0:
        return -1
    if grid[0][0] == 1 or grid[n - 1][n - 1] == 1:
        return -1
    visited = [[False] * n for _ in range(n)]
    visited[0][0] = True
    q = deque([(0, 0, 0)])
    while q:
        r, c, steps = q.popleft()
        if r == n - 1 and c == n - 1:
            return steps
        for dr, dc in ((-1, 0), (1, 0), (0, -1), (0, 1)):
            nr, nc = r + dr, c + dc
            if 0 <= nr < n and 0 <= nc < n and not visited[nr][nc] and grid[nr][nc] == 0:
                visited[nr][nc] = True
                q.append((nr, nc, steps + 1))
    return -1

Time complexity: O(n^2) — each of the n*n cells is enqueued at most once.. Space complexity: O(n^2) — the visited matrix and the BFS queue..

Hints

  1. With unit-cost moves, BFS finds the shortest path; DFS does not guarantee minimality.
  2. Mark a cell visited at enqueue time (not dequeue) to avoid pushing it multiple times.
  3. Check the start and end cells up front — if either is blocked, the answer is -1.
  4. Track the step count alongside each cell in the queue, or do level-by-level BFS.

Count All Distinct Simple Paths in an Obstacle Grid (Follow-up)

Follow-up to the grid problem: instead of the shortest path, count ALL distinct simple paths (paths that never revisit a cell) from the top-left `(0, 0)` to the bottom-right `(n - 1, n - 1)`, using the same four-directional movement over free cells. Return the number of such paths. Implement `solution(grid)` returning the count of distinct simple paths. Use DFS with backtracking: mark a cell visited on entry, recurse into all free unvisited neighbors, and unmark it on exit so other paths can reuse it. Each time you reach the destination, increment the count. The number of simple paths can be exponential in n, so this is exhaustive enumeration suitable only for small grids — discuss this scalability limit in an interview.

Constraints

  • 1 <= n (grid is square, n x n)
  • Each cell is 0 (free) or 1 (blocked)
  • A simple path may not revisit any cell
  • Movement is restricted to the four cardinal directions
  • Return 0 if the start or end is blocked, or no path exists; a 1x1 free grid has exactly 1 path

Examples

Input: ([[0]],)

Expected Output: 1

Explanation: The start is the destination, which counts as one trivial path.

Input: ([[0, 0], [0, 0]],)

Expected Output: 2

Explanation: Right-then-down and down-then-right are the two distinct simple paths.

Input: ([[0, 1], [1, 0]],)

Expected Output: 0

Explanation: Both moves from the start are blocked, so no path reaches the destination.

Input: ([[0, 0, 0], [0, 0, 0], [0, 0, 0]],)

Expected Output: 12

Explanation: An open 3x3 grid has 12 distinct self-avoiding paths from one corner to the opposite corner.

Input: ([[1, 0], [0, 0]],)

Expected Output: 0

Explanation: The start cell is blocked, so no path can begin.

Input: ([[0, 0, 0], [1, 1, 0], [0, 0, 0]],)

Expected Output: 1

Explanation: The wall of obstacles forces a single corridor, leaving exactly one simple path.

Solution

def solution(grid):
    n = len(grid)
    if n == 0:
        return 0
    if grid[0][0] == 1 or grid[n - 1][n - 1] == 1:
        return 0
    visited = [[False] * n for _ in range(n)]
    count = 0

    def dfs(r, c):
        nonlocal count
        if r == n - 1 and c == n - 1:
            count += 1
            return
        for dr, dc in ((-1, 0), (1, 0), (0, -1), (0, 1)):
            nr, nc = r + dr, c + dc
            if 0 <= nr < n and 0 <= nc < n and not visited[nr][nc] and grid[nr][nc] == 0:
                visited[nr][nc] = True
                dfs(nr, nc)
                visited[nr][nc] = False

    visited[0][0] = True
    dfs(0, 0)
    return count

Time complexity: O(4^(n^2)) in the worst case — there can be exponentially many simple paths, and each is enumerated explicitly.. Space complexity: O(n^2) for the visited matrix plus O(n^2) recursion depth (a simple path visits at most every cell once)..

Hints

  1. This is exhaustive enumeration, not a shortest-path problem — DFS with backtracking is the natural fit.
  2. Mark the current cell visited before recursing and UNMARK it after returning, so the cell is free for sibling branches.
  3. Increment the counter only when you reach (n-1, n-1); do not stop early, since you want every path.
  4. Because the count of simple paths grows exponentially with grid size, this only scales to small n — mention this limitation in an interview rather than claiming a polynomial bound.
Last updated: Jun 21, 2026

Loading coding console...

PracHub

Master your tech interviews with 8,000+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities
  • Student Access

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.

Related Coding Questions

  • Find Shortest Unique Prefixes - Meta (medium)
  • Compute Exclusive Execution Times - Meta (medium)
  • Solve Tree Columns And Maze Variants - Meta (medium)
  • Solve Tree Diameter and Palindromic Counts - Meta (medium)
  • Simulate Monster Team Battles - Meta (hard)