Katkat

Find Shared Motion Periods Across Camera Streams

ServalSoftware Engineer · Technical Screen

Last updated

Tests your ability to parse thresholded time-series sensor data into continuous intervals and compute multi-way interval intersections.

Problem Statement

You are monitoring a fleet of security cameras. Each camera produces a time-series list of sensor readings represented as (timestamp, intensity), sorted in ascending order by timestamp. Here, timestamp is an integer (e.g., in seconds or milliseconds), and intensity is a float between 0.0 and 1.0 indicating motion.

Given a list of streams streams, an intensity threshold threshold, and a maximum allowed gap max_gap between consecutive readings:

  1. Extract Active Intervals for each stream:

    • A reading is active if intensity >= threshold.
    • Two consecutive active readings at timestamps t_prev and t_curr belong to the same continuous active interval if t_curr - t_prev max_gap, the current interval closes at t_prev, and a new interval begins at t_curr.
    • An isolated active reading at t forms a closed interval [t, t].
  2. Compute Shared Intervals:

    • Find all closed time intervals [start, end] where all cameras in streams are simultaneously active.
    • A single-point overlap [t, t] is valid if all cameras are active at time t.
    • Return the shared intervals in chronological order. Non-overlapping or touching intervals that can be merged should be merged.

Do not mutate the input lists.

Function Signature

def find_shared_motion_periods(
    streams: list[list[tuple[int, float]]],
    threshold: float,
    max_gap: int
) -> list[tuple[int, int]]:
    pass

Constraints

  • 0 <= len(streams) <= 100
  • Each stream has 0 <= len(stream) <= 10^4 readings.
  • Timestamps in each stream are strictly increasing non-negative integers: 0 <= timestamp <= 10^9.
  • 0.0 <= intensity <= 1.0
  • 0.0 <= threshold <= 1.0
  • 0 <= max_gap <= 10^6

Examples

Example 1

streams = [
    [(10, 0.8), (14, 0.9), (20, 0.7), (25, 0.2)],
    [(12, 0.6), (15, 0.8), (18, 0.9), (30, 0.9)]
]
threshold = 0.5
max_gap = 5

# Stream 0 active readings: 10, 14, 20 (gaps: 14-10=4  5)
# Stream 0 intervals: [10, 14], [20, 20]
# Stream 1 active readings: 12, 15, 18, 30 (gaps: 15-12=3  5)
# Stream 1 intervals: [12, 18], [30, 30]
# Intersection of [10, 14] & [20, 20] with [12, 18] & [30, 30]:
# Output: [(12, 14)]

Example 2

streams = [
    [(5, 0.8)],
    [(5, 0.9)]
]
threshold = 0.7
max_gap = 2

# Both have isolated readings at t=5.
# Output: [(5, 5)]

Hints

Hint 1

Break the problem into two distinct steps: first convert each stream into a sorted list of disjoint closed intervals `[start, end]`, then find the intersection across all lists.

Hint 2

For pairwise interval intersection, use a two-pointer approach comparing the current interval from list A and list B: compute `max(start_A, start_B)` and `min(end_A, end_B)`, advancing the pointer of whichever interval ends earlier.

Hint 3

To intersect `k` streams, you can either intersect streams sequentially (`res = intersect(res, next_stream)`) or use a min-heap / sweep-line event algorithm.

Follow-up questions

  • How would you handle streams delivering readings out of order or with clock skew between cameras?
  • If camera streams are infinite live streams, how would you adapt this algorithm into an online streaming service with bounded memory?
  • Suppose we want intervals where at least `M` out of `N` cameras detected motion (majority voting). How does your approach change?