Bird
Raised Fist0
Interview Prepcustom-data-structureshardGoogleAmazon

Range Module (Add/Remove/Query Ranges)

Choose your preparation mode4 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Steps
setup

Initialize empty RangeModule

Create an empty RangeModule with no intervals and an empty starts list.

💡 Starting with an empty structure is essential to see how intervals are added and managed.
Line:self.intervals = dict() self.starts = []
💡 Intervals and starts are empty, so no coverage exists yet.
📊
Range Module (Add/Remove/Query Ranges) - Watch the Algorithm Execute, Step by Step
Watching each pointer movement and interval update helps you understand how overlapping intervals are merged or split, which is hard to grasp from code alone.
Step 1/16
·Active fillAnswer cell
setup
advance
compare
compare
insert
10
advance
10
prune
10
prune
10
detach
insert
10
16
compare
10
16
compare
10
16
Result: true
compare
10
16
compare
10
16
Result: false
compare
10
16
compare
10
16
Result: true

Key Takeaways

Intervals are stored as a sorted list of start points with corresponding ends, enabling efficient merging and splitting.

This structure is hard to visualize from code alone but becomes clear when watching intervals merge and split step-by-step.

Adding a range merges all overlapping intervals into one, simplifying coverage representation.

Seeing how bisect finds indices and how intervals are removed and replaced clarifies the merging process.

Removing a range can split existing intervals into two, preserving coverage outside the removed range.

The split and reinsert steps are subtle in code but become obvious when watching the intervals being pruned and reinserted.

Practice

(1/5)
1. Consider the following Python code snippet for the MedianFinder class using two heaps. After adding the numbers 1, 5, and 3 in that order, what is the value of the median returned by findMedian()?
easy
A. 1.0
B. 3.0
C. 5.0
D. 2.0

Solution

  1. Step 1: Insert 1

    Low heap empty, push -1 to low; low_size=1, high_size=0.
  2. Step 2: Insert 5

    5 > -low[0] (which is 1), push 5 to high; low_size=1, high_size=1; heaps balanced.
  3. Step 3: Insert 3

    3 <= 5 but > 1, push 3 to high; high_size=2, low_size=1; balance heaps by moving smallest from high (3) to low (-3); low_size=2, high_size=1.
  4. Step 4: Find median

    low_size > high_size, median is -low[0] = 3.0.
  5. Step 5: Re-examine median calculation

    After balancing, low heap has [-3, -1], high heap has [5]. Median is top of low heap = 3.0, but the question asks for median after adding 1,5,3 in order, so median is 3.0.
  6. Final Answer:

    Option B -> Option B
  7. Quick Check:

    Median after [1,5,3] is 3.0 [OK]
Hint: Median is top of larger heap after balancing [OK]
Common Mistakes:
  • Forgetting to balance heaps after insertion
  • Returning wrong heap top for median
2. What is the time complexity of the get and put operations in an optimal LRU Cache implementation using a hash map and a doubly linked list with capacity n?
medium
A. O(n) for get and put due to list traversal
B. O(1) amortized for get and put using hash map and doubly linked list
C. O(log n) due to balancing the linked list
D. O(1) for get but O(n) for put due to eviction

Solution

  1. Step 1: Analyze get operation

    Hash map provides O(1) access to node; doubly linked list allows O(1) removal and insertion to update usage order.
  2. Step 2: Analyze put operation

    Insertion involves hash map update and linked list insertion/removal, all O(1). Eviction removes tail node in O(1).
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Both get and put run in constant time using combined data structures [OK]
Hint: Hash map + doubly linked list -> O(1) get and put [OK]
Common Mistakes:
  • Assuming list removal is O(n)
  • Confusing amortized with worst-case
  • Thinking linked list needs balancing
3. Suppose the linked list with random pointers can contain cycles formed by random pointers (i.e., random pointers may create cycles independent of next pointers). Which approach correctly copies such a list without infinite loops or duplicate nodes?
hard
A. Use the optimal weaving approach as is, since it handles all cases in O(1) space.
B. Use a recursive approach with memoization to track already copied nodes and avoid infinite recursion.
C. Use the brute force approach but skip assigning random pointers to avoid cycles.
D. Modify the optimal approach to break cycles by removing random pointers before copying.

Solution

  1. Step 1: Understand cycle implications

    Random pointer cycles cause infinite loops if naive traversal is used without tracking visited nodes.
  2. Step 2: Identify safe approach

    Recursive copying with memoization tracks visited nodes, preventing infinite recursion and duplicate copies.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Memoization ensures each node is copied once even with cycles [OK]
Hint: Memoization prevents infinite recursion in cyclic graphs [OK]
Common Mistakes:
  • Assuming weaving approach handles cycles safely
  • Ignoring cycles and causing infinite loops
  • Removing random pointers loses information
4. Suppose the stack is modified to allow reusing popped elements by pushing them back later, and the increment operation must still work correctly. Which modification to the optimal lazy increment approach is necessary to maintain correctness?
hard
A. Store increments per element rather than per index, requiring a more complex data structure.
B. Reset the entire increments array to zero on each push to avoid stale increments.
C. Track increments with a stack of (index, increment) pairs and apply them on pop accordingly.
D. No change needed; the existing lazy increment array works correctly with reused elements.

Solution

  1. Step 1: Understand reuse impact

    Reusing popped elements means the same stack positions may hold different elements over time, so increments per index become invalid.
  2. Step 2: Modify increment tracking

    To maintain correctness, increments must be tracked per element, not per index, requiring a data structure that associates increments with elements themselves.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Per-element increments prevent stale increment application on reused positions [OK]
Hint: Reusing elements breaks index-based increments; track per element [OK]
Common Mistakes:
  • Assuming no change needed
  • Resetting increments array loses valid increments
5. Suppose the Twitter design is extended so that users can post the same tweet multiple times (tweet reuse allowed). Which modification to the optimal approach is necessary to correctly handle this scenario?
hard
A. Allow multiple TweetNode instances with the same tweetId but different timestamps in the linked list and heap.
B. Use a hash set to track unique tweetIds per user to avoid duplicates in the feed.
C. Modify the heap to store tweetIds only once, ignoring repeated posts of the same tweetId.
D. Disallow posting duplicate tweetIds by rejecting posts with existing tweetIds.

Solution

  1. Step 1: Understand tweet reuse impact

    Allowing duplicate tweetIds means multiple posts with same id but different times must be treated as distinct tweets.
  2. Step 2: Adjust data structures

    Each post creates a new TweetNode with unique timestamp; heap and linked lists handle duplicates naturally by time ordering.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Multiple nodes with same tweetId but different times must be stored separately [OK]
Hint: Treat each post as unique by timestamp, even if tweetId repeats [OK]
Common Mistakes:
  • Trying to deduplicate tweets in feed incorrectly
  • Rejecting duplicate posts unnecessarily