A fintech super-app serves 20M+ mobile DAUs through an in-app webview. To reduce latency and battery drain, the frontend batches calls to mobile-specific web APIs (e.g., Geolocation, DeviceOrientation, Vibration) and ships them to an on-device aggregator before sending a compact payload to the backend.
However, the aggregator must deduplicate events that are effectively the same (e.g., multiple geolocation reads within a few seconds) while preserving the order in which distinct user actions occurred. Your task is to implement the core merge logic.
You are given a list of API event records in chronological order:
events[i] = [t_i, api_i, payload_i]
t_i is an integer timestamp in milliseconds (non-decreasing)api_i is a string (e.g., "geo", "orient", "vibrate")payload_i is a string (opaque; treat as exact-match)You are also given an integer window_ms.
Two events A and B are considered mergeable if:
A.api == B.apiA.payload == B.payloadB.t - A.t <= window_msWhen events are mergeable, they should be merged into a single output record:
[start_t, end_t, api, payload, count]
start_t = timestamp of the first event in the merged groupend_t = timestamp of the last event in the merged groupcount = number of merged eventsMerging is only allowed for contiguous runs in the input. If a different event appears in between, you must not merge across it even if timestamps and fields match.
Return the merged list.
Input:
events = [[1000,"geo","A"],[1200,"geo","A"],[2000,"orient","x"],[2100,"geo","A"]]window_ms = 500Output:
[[1000,1200,"geo","A",2],[2000,2000,"orient","x",1],[2100,2100,"geo","A",1]]Explanation:
The first two geo/A events are contiguous and within 500ms, so they merge. The final geo/A cannot merge with them because an orient/x event breaks contiguity.
Input:
events = [[0,"vibrate","50"],[400,"vibrate","50"],[1200,"vibrate","50"],[1300,"vibrate","60"]]window_ms = 500Output:
[[0,400,"vibrate","50",2],[1200,1200,"vibrate","50",1],[1300,1300,"vibrate","60",1]]Explanation: The first two merge (400ms apart). The third is 800ms after the first, so it starts a new group. Different payloads never merge.
t_i non-decreasing).payload as an opaque string; no parsing.events = [(1000,"geo","A"),(1200,"geo","A"),(2000,"orient","x"),(2100,"geo","A")], window_ms = 500Output[(1000,1200,"geo","A",2),(2000,2000,"orient","x",1),(2100,2100,"geo","A",1)]WhyFirst two events merge; the orientation event breaks contiguity so the last geo event stands alone.events = [(0,"vibrate","50"),(400,"vibrate","50"),(1200,"vibrate","50"),(1300,"vibrate","60")], window_ms = 500Output[(0,400,"vibrate","50",2),(1200,1200,"vibrate","50",1),(1300,1300,"vibrate","60",1)]WhyThe 0 and 400ms events merge; 1200ms is too far from 400ms to merge; payload change prevents merging.0 <= len(events) <= 2 * 10^5events[i] = [t_i, api_i, payload_i] with t_i an integer and t_i is non-decreasing0 <= t_i <= 10^121 <= len(api_i) <= 200 <= len(payload_i) <= 2000 <= window_ms <= 10^9