Find Consecutive Integers from a Data Stream
MedPrompt
For a stream of integers, implement a data structure that checks if the last k integers parsed in the stream are equal to value.
Implement the DataStream class:
DataStream(int value, int k)Initializes the object with an empty integer stream and the two integersvalueandk.boolean consec(int num)Addsnumto the stream of integers. Returnstrueif the lastkintegers are equal tovalue, andfalseotherwise. If there are less thankintegers, the condition does not hold true, so returnsfalse.
Example 1:
Input
["DataStream", "consec", "consec", "consec", "consec"]
[[4, 3], [4], [4], [4], [3]]
Output
[null, false, false, true, false]
Explanation
DataStream dataStream = new DataStream(4, 3); //value = 4, k = 3
dataStream.consec(4); // Only 1 integer is parsed, so returns False.
dataStream.consec(4); // Only 2 integers are parsed.
// Since 2 is less than k, returns False.
dataStream.consec(4); // The 3 integers parsed are all equal to value, so returns True.
dataStream.consec(3); // The last k integers parsed in the stream are [4,4,3].
// Since 3 is not equal to value, it returns False.
Constraints:
1 <= value, num <= 1091 <= k <= 105- At most
105calls will be made toconsec.
Approaches
2 approaches with complexity analysis and trade-offs.
This approach involves maintaining a data structure, specifically a queue, to keep track of the most recent k integers from the stream. For each new integer, we add it to the queue and ensure the queue's size does not exceed k. Then, we check if the queue has exactly k elements and if all of them are equal to the target value.
Algorithm
- Initialize
value,k, and an empty queuestream. - For each call to
consec(num):- Add
numto thestream. - If
stream.size() > k, remove the head of the queue. - If
stream.size() < k, returnfalse. - Iterate through each element
xin thestream:- If
x != value, returnfalse.
- If
- Return
true.
- Add
Walkthrough
We initialize the DataStream with value, k, and a queue (like LinkedList or ArrayDeque).
In the consec(num) method:
- Add the new integer
numto the end of the queue. - If the queue's size becomes larger than
k, remove the element from the front. This keeps the queue containing only the lastk(or fewer) elements. - Check if the current size of the queue is less than
k. If it is, we haven't seen enough elements yet, so we returnfalse. - If the size is
k, we iterate through all elements in the queue. If any element is not equal to the targetvalue, we returnfalse. - If the loop completes without finding any mismatch, it means all
kelements are equal tovalue, so we returntrue.
import java.util.Queue;import java.util.LinkedList; class DataStream { private int value; private int k; private Queue<Integer> stream; public DataStream(int value, int k) { this.value = value; this.k = k; this.stream = new LinkedList<>(); } public boolean consec(int num) { stream.add(num); if (stream.size() > k) { stream.poll(); } if (stream.size() < k) { return false; } for (int n : stream) { if (n != this.value) { return false; } } return true; }}Complexity
Time
O(k) for each call to `consec`. Adding to and removing from the queue takes O(1) time, but the check requires iterating through all `k` elements in the queue in the worst case.
Space
O(k) to store the last `k` elements in the queue.
Trade-offs
Pros
Conceptually simple and easy to implement.
Correctly solves the problem by directly simulating the condition.
Cons
Inefficient for large values of
kas eachconseccall takes time proportional tok.Uses more memory than necessary, as we only need to know if the streak is maintained, not the actual numbers.
A more efficient approach is to avoid storing the actual numbers. Instead, we can just maintain a count of how many consecutive times the target value has appeared at the end of the stream. This eliminates the need for a separate data structure and reduces the time complexity of each check to constant time.
Algorithm
- Initialize
value,k, and a countercount = 0. - For each call to
consec(num):- If
num == value, incrementcount. - Else, reset
countto 0. - Return
trueifcount >= k, otherwise returnfalse.
- If
Walkthrough
We initialize the DataStream with value, k, and a counter variable, say count, set to 0.
In the consec(num) method:
- We check if the incoming integer
numis equal to our targetvalue. - If
num == value, it means the consecutive streak continues, so we incrementcount. - If
num != value, the streak is broken. We must resetcountto 0. - After updating the counter, we check if
countis greater than or equal tok. If it is, this implies that the lastk(or more) numbers were all equal tovalue, so we returntrue. Otherwise, we returnfalse.
class DataStream { private int value; private int k; private int count; public DataStream(int value, int k) { this.value = value; this.k = k; this.count = 0; } public boolean consec(int num) { if (num == this.value) { this.count++; } else { this.count = 0; } return this.count >= this.k; }}Complexity
Time
O(1) for each call to `consec`. Each call involves a few simple arithmetic operations and comparisons, which are constant time operations.
Space
O(1) extra space. We only need to store the counter, `value`, and `k`, which is constant space regardless of the number of calls or the value of `k`.
Trade-offs
Pros
Extremely efficient with O(1) time and space complexity.
Simple logic that is easy to implement and maintain.
Cons
There are no significant cons to this approach as it is optimal for the given problem constraints.
Solutions
Solution
class DataStream { private int cnt ; private int val ; private int k ; public DataStream ( int value , int k ) { val = value ; this . k = k ; } public boolean consec ( int num ) { cnt = num == val ? cnt + 1 : 0 ; return cnt >= k ; } } /** * Your DataStream object will be instantiated and called as such: * DataStream obj = new DataStream(value, k); * boolean param_1 = obj.consec(num); */class DataStream { public: DataStream ( int value , int k ) { val = value ; this -> k = k ; } bool consec ( int num ) { cnt = num == val ? cnt + 1 : 0 ; return cnt >= k ; } private: int cnt = 0 ; int val , k ; }; /** * Your DataStream object will be instantiated and called as such: * DataStream* obj = new DataStream(value, k); * bool param_1 = obj->consec(num); */class DataStream : def __init__ ( self , value : int , k : int ): self . val , self . k = value , k self . cnt = 0 def consec ( self , num : int ) -> bool : self . cnt = 0 if num != self . val else self . cnt + 1 return self . cnt >= self . k # Your DataStream object will be instantiated and called as such: # obj = DataStream(value, k) # param_1 = obj.consec(num)Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.