Write an iterator that iterates through a run-length encoded sequence.
The iterator is initialized by RLEIterator(int[] A)
, where A
is a run-length encoding of some sequence. More specifically, for all even i
, A[i]
tells us the number of times that the non-negative integer value A[i+1]
is repeated in the sequence.
The iterator supports one function: next(int n)
, which exhausts the next n
elements (n >= 1
) and returns the last element exhausted in this way. If there is no element left to exhaust, next
returns -1
instead.
For example, we start with A = [3,8,0,9,2,5]
, which is a run-length encoding of the sequence [8,8,8,5,5]
. This is because the sequence can be read as "three eights, zero nines, two fives".
Idea 1.a Bruteforce, using queue simulate the exhausting operation
class RLEIterator {
private Deque<Integer> buffer;
public RLEIterator(int[] A) {
buffer = new LinkedList<>();
for(int i = 1; i < A.length; i+=2) {
int cnt = A[i-1];
int value = A[i];
while(cnt > 0) {
buffer.offerLast(value);
--cnt;
}
}
} public int next(int n) {
Integer value = null;
while(n > 0) {
value = buffer.pollFirst();
--n;
}
return value == null? -1: value;
}
}
Idea 1.b too much space and very slow to remove element one by one, the key is to find the index of last exhausted element, once we know the current index and remaining elements on the current index, we can get the result
A[currIndex+1] if remaining >= n
n -= remaining; remaining = A[currIndex + 2]; currIndex += 2, moving to the next element
Time complexity: O(N + Q), N = A.length, Q = number of calls to next()
Space complexity: O(N)
class RLEIterator {
private int remaining;
private int currIndex;
private int[] A;
public RLEIterator(int[] A) {
remaining = A[0];
currIndex = 0;
this.A = A;
} public int next(int n) {
while(currIndex < A.length) {
if(remaining < n) {
n -= remaining;
currIndex += 2;
if(currIndex < A.length) {
remaining = A[currIndex];
}
}
else {
remaining -= n;
return A[currIndex+1];
}
} return -1;
}
}
Idea 1.c instead of storing the remaining elements, storing the exhausted elements which represents that exhausted elements of A[currIndex+1] are exhausted, hence the next exhausted = 0 for next element, saving checking index to get A[currIndex] for the next remaining
Time complexity: O(N + Q)
Space complexity: O(N)
class RLEIterator {
private int exhausted;
private int currIndex;
private int[] A;
public RLEIterator(int[] A) {
exhausted = 0;
currIndex = 0;
this.A = A;
} public int next(int n) {
while(currIndex < A.length) {
if(A[currIndex] - exhausted < n) {
n -= A[currIndex] - exhausted;
currIndex += 2;
exhausted = 0;
}
else {
exhausted += n;
return A[currIndex+1];
}
} return -1;
}
}
Idea 1.d Modifying the Array
class RLEIterator {
private int currIndex;
private int[] A;
public RLEIterator(int[] A) {
currIndex = 0;
this.A = A;
} public int next(int n) {
while(currIndex < A.length) {
if(A[currIndex] < n) {
n -= A[currIndex];
currIndex += 2;
}
else {
A[currIndex] -= n;
return A[currIndex+1];
}
} return -1;
}
}
which style would you prefer?
class RLEIterator {
private int currIndex;
private int[] A;
public RLEIterator(int[] A) {
currIndex = 0;
this.A = A;
} public int next(int n) {
while(currIndex < A.length && A[currIndex] < n) {
n -= A[currIndex];
currIndex += 2;
} if(currIndex < A.length) {
A[currIndex] -= n;
return A[currIndex+1];
} return -1;
}
}
Example 1:
Input: ["RLEIterator","next","next","next","next"], [[[3,8,0,9,2,5]],[2],[1],[1],[2]]
Output: [null,8,8,5,-1]
Explanation:
RLEIterator is initialized with RLEIterator([3,8,0,9,2,5]).
This maps to the sequence [8,8,8,5,5].
RLEIterator.next is then called 4 times: .next(2) exhausts 2 terms of the sequence, returning 8. The remaining sequence is now [8, 5, 5]. .next(1) exhausts 1 term of the sequence, returning 8. The remaining sequence is now [5, 5]. .next(1) exhausts 1 term of the sequence, returning 5. The remaining sequence is now [5]. .next(2) exhausts 2 terms, returning -1. This is because the first term exhausted was 5,
but the second term did not exist. Since the last term exhausted does not exist, we return -1.
Note:
0 <= A.length <= 1000
-
A.length
is an even integer. 0 <= A[i] <= 10^9
- There are at most
1000
calls toRLEIterator.next(int n)
per test case. - Each call to
RLEIterator.next(int n)
will have1 <= n <= 10^9
.