Katkat

Mark and Compact a Heap-Indexed Subtree

PinterestSoftware Engineer · Online Assessment

Last updated

This problem tests array manipulation, heap-based tree traversal, and stable partitioning techniques while requiring memory efficiency without modifying the original input.

Problem Statement

You are given an array heap of integers representing a binary tree stored as a heap. In this representation, the node at index i has its left child at 2*i + 1 and its right child at 2*i + 2.

Given an index target and the heap array, perform the following two operations without mutating the original input:

  1. Marking: Identify the target node and all of its descendants in the tree. Create a new array where these nodes are replaced with the value -1.
  2. Compacting: Create a second array containing only the elements that were not marked (i.e., those that were not the target or its descendants), maintaining their original relative order.

Function Signature

def process_heap(heap: List[int], target: int) -> Tuple[List[int], List[int]]:

Constraints

  • 0 <= target < len(heap)
  • heap length up to 10^5
  • Elements in heap are non-negative integers.

Examples

Example 1: Input: heap = [10, 20, 30, 40, 50], target = 1

  • Node 1 (value 20) has children at 2*1+1=3 (value 40) and 2*1+2=4 (value 50).
  • Marked: Indices {1, 3, 4}.
  • Marked Array: [10, -1, 30, -1, -1]
  • Compacted Array: [10, 30]

Example 2: Input: heap = [5, 2, 8], target = 0

  • Node 0 has children at 1 and 2. All nodes are marked.
  • Marked Array: [-1, -1, -1]
  • Compacted Array: []

Edge Cases

  • target is a leaf node.
  • target is the root node.
  • heap is empty or contains a single element.

Hints

Hint 1

Use a queue or recursion to traverse the subtree starting from the target index using the heap property i -> 2i+1, 2i+2.

Hint 2

Store the indices of the marked nodes in a boolean array or a set to perform lookups in O(1) time.

Hint 3

Construct the output arrays by iterating through the original array once and checking your marked set to decide whether to append -1 or the original value to the respective lists.

Follow-up questions

  • How would you optimize the memory complexity if the input array is extremely large and you can only afford O(subtree_size) extra space?
  • If the tree was not a complete binary tree but a general tree represented by an adjacency list, how would your traversal strategy change?
  • What are the implications for cache performance if we perform this operation on an array that exceeds the CPU L3 cache size?