Data Stream as Disjoint Intervals - Complete Solution Guide
Data Stream as Disjoint Intervals is LeetCode problem 352, a Hard level challenge. This complete guide provides step-by-step explanations, multiple solution approaches, and optimized code in python3, java, cpp, c.
Problem Statement
Given a data stream input of non-negative integers a 1 , a 2 , ..., a n , summarize the numbers seen so far as a list of disjoint intervals. Implement the SummaryRanges class: SummaryRanges() Initializes the object with an empty stream. void addNum(int value) Adds the integer value to the stream. int[][] getIntervals() Returns a summary of the integers in the stream currently as a list of disjoint intervals [start i , end i ] . The answer should be sorted by start i . Example 1: Input ["SummaryR
Detailed Explanation
The problem requires you to maintain a summary of a stream of non-negative integers as a list of disjoint intervals. The `SummaryRanges` class needs to implement three functionalities: `SummaryRanges()` to initialize an empty stream, `addNum(int value)` to add an integer to the stream, and `getIntervals()` to return a list of disjoint intervals representing the numbers seen so far, sorted by the start of each interval. The integers are constrained to be between 0 and 10000, and there are constraints on the number of calls to `addNum` and `getIntervals`.
Solution Approach
The provided solution uses a boolean array `seen` to keep track of whether a number has been added to the stream. When `addNum(value)` is called, the corresponding entry in `seen` is set to `true`. The `getIntervals()` method iterates through the `seen` array, building intervals by finding consecutive `true` values. The 'dirty' flag optimizes the process by ensuring that the interval list is only recalculated when a new number is added. This approach leverages the constrained input range to provide an efficient solution.
Step-by-Step Algorithm
- Step 1: Initialize a boolean array `seen` of size 10001 with all values set to `false`. Also, initialize a boolean flag `dirty` to `true` and a list to store the disjoint intervals.
- Step 2: `addNum(value)`: Check if `seen[value]` is `false`. If it is, set `seen[value]` to `true` and set `dirty` to `true`.
- Step 3: `getIntervals()`: Check the `dirty` flag. If it's `false`, return the previously calculated list of intervals.
- Step 4: If `dirty` is `true`, clear the existing list of intervals.
- Step 5: Iterate through the `seen` array from index 0 to 10000.
- Step 6: If `seen[i]` is `true`, start a new interval with `start = i` and continue iterating to find the end of the interval.
- Step 7: Set `j = i` and increment `j` as long as `j + 1 < 10001` and `seen[j + 1]` is `true`.
- Step 8: The end of the interval is `j`. Add the interval `[start, j]` to the list of intervals.
- Step 9: Set `i = j + 1` to skip over the just-processed interval.
- Step 10: If `seen[i]` is `false`, simply increment `i` to check the next number.
- Step 11: After iterating through the entire `seen` array, set `dirty` to `false` and return the list of intervals.
Key Insights
- Insight 1: Use a boolean array to efficiently track the presence of each number within the given range (0 to 10000). This allows for quick checks when constructing intervals.
- Insight 2: Implement a 'dirty' flag to avoid recomputing the intervals unnecessarily. Only recalculate when a new number has been added since the last call to `getIntervals()`.
- Insight 3: Linear scan is sufficient since the constraints on value (0 to 10000) allow for a fixed-size array. More complex data structures like balanced trees could be used for a wider range, but are not necessary here.
Complexity Analysis
Time Complexity: O(n)
Space Complexity: O(n)
Topics
This problem involves: Binary Search, Design, Ordered Set.
Companies
Asked at: Databricks.