PracHub
QuestionsPremiumCoachesLearningGuidesInterview Prep

Quick Overview

These tasks evaluate core competencies in directed graph algorithms (topological ordering and cycle detection) and binary tree traversals (boundary identification and leaf enumeration), testing understanding of dependency modeling and traversal patterns.

  • medium
  • Snowflake
  • Coding & Algorithms
  • Software Engineer

Implement topological sort and tree boundary traversal

Company: Snowflake

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Technical Screen

You are given two separate coding tasks. ## Problem A — Order courses with prerequisites You have `n` courses labeled `0..n-1` and a list of prerequisite pairs `prerequisites`, where each pair `[a, b]` means **to take course `a`, you must first take course `b`**. **Task:** Return **any valid ordering** of all courses that satisfies prerequisites. If it is impossible (because of a cycle), return an **empty list**. **Input:** - `n` (integer) - `prerequisites` (list of pairs) **Output:** - A list of length `n` representing a valid order, or `[]` if no order exists. **Constraints (typical):** - `1 ≤ n ≤ 10^5` - `0 ≤ len(prerequisites) ≤ 2*10^5` **Notes:** - Implement the algorithm yourself (e.g., topological sort). - Be prepared to write a few basic tests (e.g., cycle case, disconnected graph). --- ## Problem B — Boundary traversal of a (complete/balanced) binary tree You are given the root of a binary tree. The tree is guaranteed to be **complete and balanced** (interview variant constraint), but your solution may work for any binary tree. Define the **boundary** of the tree in **anti-clockwise** order as: 1. The **root** (once). 2. The **left boundary** (excluding leaves): from `root.left` going downward, always taking the next boundary node. 3. All **leaf nodes** from left to right. 4. The **right boundary** (excluding leaves): from `root.right` going downward, collected top-down but output **bottom-up**. **Task:** Return a list of node values in boundary order, with **no duplicates**. **Input:** - `root` of a binary tree **Output:** - List of integers representing the boundary traversal. **Edge cases to consider:** - Single-node tree - Root has only one child - Trees where left/right boundary paths include missing children (even if the interview variant says complete) **Complexity target:** - Time `O(N)`, space `O(H)` (recursion) or `O(N)` worst case depending on implementation.

Quick Answer: These tasks evaluate core competencies in directed graph algorithms (topological ordering and cycle detection) and binary tree traversals (boundary identification and leaf enumeration), testing understanding of dependency modeling and traversal patterns.

Part 1: Order Courses With Prerequisites

You are given n courses labeled 0 through n - 1 and a list of prerequisite pairs. Each pair [a, b] means course b must be taken before course a. Return an ordering of all courses that satisfies every prerequisite. If no such ordering exists because the prerequisite graph contains a cycle, return an empty list. If multiple valid orderings exist, any valid ordering is acceptable; the reference solution below uses a min-heap to choose the smallest currently available course.

Constraints

  • 1 <= n <= 100000
  • 0 <= len(prerequisites) <= 200000
  • 0 <= course, prerequisite < n for every prerequisite pair
  • The graph may be disconnected
  • The graph may contain cycles

Examples

Input: (1, [])

Expected Output: [0]

Explanation: A single course with no prerequisites can be taken immediately.

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

Expected Output: [0, 1, 2, 3]

Explanation: Course 0 must come before 1 and 2, and both 1 and 2 must come before 3.

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

Expected Output: []

Explanation: Course 0 depends on 1 and course 1 depends on 0, forming a cycle.

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

Expected Output: [0, 1, 2, 3, 4]

Explanation: There are two independent prerequisite chains and one isolated course.

Input: (3, [])

Expected Output: [0, 1, 2]

Explanation: With no prerequisites, all courses are immediately available.

Solution

def solution(n, prerequisites):
    import heapq

    graph = [[] for _ in range(n)]
    indegree = [0] * n

    for course, prereq in prerequisites:
        graph[prereq].append(course)
        indegree[course] += 1

    available = [course for course in range(n) if indegree[course] == 0]
    heapq.heapify(available)

    order = []

    while available:
        course = heapq.heappop(available)
        order.append(course)

        for next_course in graph[course]:
            indegree[next_course] -= 1
            if indegree[next_course] == 0:
                heapq.heappush(available, next_course)

    if len(order) != n:
        return []

    return order

Time complexity: O((n + m) log n), where m is len(prerequisites), because each course may be pushed/popped from the heap and each edge is processed once.. Space complexity: O(n + m) for the adjacency list, indegree array, heap, and result..

Hints

  1. Track how many prerequisites each course still has using an indegree array.
  2. Courses with indegree 0 can be taken immediately; if you cannot process all courses, a cycle exists.

Part 2: Boundary Traversal of a Binary Tree

You are given a binary tree and must return its boundary in anti-clockwise order with no duplicate nodes. The boundary consists of: the root once, the left boundary excluding leaves, all leaves from left to right, and the right boundary excluding leaves in bottom-up order. For this coding version, the tree is provided as a standard level-order list using -1 as the missing-child sentinel. Although some interview variants guarantee the tree is complete and balanced, your solution should handle any valid binary tree shape.

Constraints

  • 0 <= len(tree) <= 100000
  • -1 is reserved as the missing-child sentinel
  • All actual node values are non-negative integers
  • The input list is a valid standard level-order encoding of a binary tree

Examples

Input: ([],)

Expected Output: []

Explanation: An empty tree has an empty boundary.

Input: ([10],)

Expected Output: [10]

Explanation: A single-node tree contains only the root.

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

Expected Output: [1, 2, 4, 5, 6, 7, 3]

Explanation: The left boundary is 2, the leaves are 4, 5, 6, 7, and the right boundary bottom-up is 3.

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

Expected Output: [1, 3, 4, 2]

Explanation: The root has only a right child. Leaves 3 and 4 are listed before the non-leaf right boundary node 2.

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

Expected Output: [1, 2, 5, 4, 3]

Explanation: The boundary follows missing-child paths correctly: left boundary 2, leaves 5 and 4, then right boundary 3.

Solution

def solution(tree):
    from collections import deque

    if not tree or tree[0] == -1:
        return []

    class Node:
        __slots__ = ('val', 'left', 'right')

        def __init__(self, val):
            self.val = val
            self.left = None
            self.right = None

    root = Node(tree[0])
    queue = deque([root])
    index = 1

    while queue and index < len(tree):
        node = queue.popleft()

        if index < len(tree):
            if tree[index] != -1:
                node.left = Node(tree[index])
                queue.append(node.left)
            index += 1

        if index < len(tree):
            if tree[index] != -1:
                node.right = Node(tree[index])
                queue.append(node.right)
            index += 1

    def is_leaf(node):
        return node.left is None and node.right is None

    result = [root.val]

    current = root.left
    while current is not None:
        if not is_leaf(current):
            result.append(current.val)
        if current.left is not None:
            current = current.left
        else:
            current = current.right

    if not is_leaf(root):
        stack = [root]
        while stack:
            node = stack.pop()
            if is_leaf(node):
                result.append(node.val)
            else:
                if node.right is not None:
                    stack.append(node.right)
                if node.left is not None:
                    stack.append(node.left)

    right_boundary = []
    current = root.right
    while current is not None:
        if not is_leaf(current):
            right_boundary.append(current.val)
        if current.right is not None:
            current = current.right
        else:
            current = current.left

    result.extend(reversed(right_boundary))
    return result

Time complexity: O(N), where N is the number of entries/nodes represented by the input tree. Each node is built and visited a constant number of times.. Space complexity: O(N) for the constructed tree and auxiliary queues/stacks..

Hints

  1. Do not add leaves while collecting the left or right boundary; collect all leaves in a separate pass to avoid duplicates.
  2. Collect the right boundary top-down into a temporary list, then reverse it before appending to the answer.
Last updated: Jun 16, 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

  • Solve Matrix and Array Distance Problems - Snowflake (medium)
  • Solve Array Distance and Wiki Navigation - Snowflake (medium)
  • Implement Document Predicate APIs - Snowflake (medium)
  • Find Shortest Wiki Click Path - Snowflake (medium)
  • Compute Inherited Role Privileges - Snowflake (hard)