题目描述
编写一个遍历游程编码序列的迭代器。
迭代器由 RLEIterator(int[] A)
初始化,其中 A
是某个序列的游程编码。更具体地,对于所有偶数 i
,A[i]
告诉我们在序列中重复非负整数值 A[i + 1]
的次数。
迭代器支持一个函数:next(int n)
,它耗尽接下来的 n
个元素(n >= 1
)并返回以这种方式耗去的最后一个元素。如果没有剩余的元素可供耗尽,则 next
返回 -1
。
例如,我们以 A = [3,8,0,9,2,5]
开始,这是序列 [8,8,8,5,5]
的游程编码。这是因为该序列可以读作 “三个八,零个九,两个五”。
样例
输入:["RLEIterator","next","next","next","next"], [[[3,8,0,9,2,5]],[2],[1],[1],[2]]
输出:[null,8,8,5,-1]
解释:
RLEIterator 由 RLEIterator([3,8,0,9,2,5]) 初始化。
这映射到序列 [8,8,8,5,5]。
然后调用 RLEIterator.next 4次。
.next(2) 耗去序列的 2 个项,返回 8。现在剩下的序列是 [8, 5, 5]。
.next(1) 耗去序列的 1 个项,返回 8。现在剩下的序列是 [5, 5]。
.next(1) 耗去序列的 1 个项,返回 5。现在剩下的序列是 [5]。
.next(2) 耗去序列的 2 个项,返回 -1。 这是由于第一个被耗去的项是 5,
但第二个项并不存在。由于最后一个要耗去的项不存在,我们返回 -1。
注意
0 <= A.length <= 1000
A.length
是偶数。0 <= A[i] <= 10^9
- 每个测试用例最多调用
1000
次RLEIterator.next(int n)
。 - 每次调用
RLEIterator.next(int n)
都有1 <= n <= 10^9
。
算法
(队列) $O(A.length)$
- 开一个队列,运行构造函数时将
A
数组中数字两个一组组成 pair 放入队列中。 - 每次调用 next,从队头开始检查;如果 n 小于等于队头中元素的个数,则队头元素个数减掉 n,若个数减为 0,则出队,最后返回该元素值即可;如果 n 大于当前队头中元素的个数,则 n 减掉队头元素的个数,队头出队,再继续检查下一个。
时间复杂度
- 当遍历完了
A
中所有的数字之后,每次就会返回 -1; - 均摊下来,最坏情况下总共只需要遍历 A 中的所有数字,故总时间复杂度为 $O(A.lenght)$。
空间复杂度
- 需要额外的队列,故空间复杂度为 $O(A.length)$。
C++ 代码
class RLEIterator {
public:
queue<pair<int, int>> num;
RLEIterator(vector<int> A) {
int n = A.size();
for (int i = 0; i < n; i += 2)
num.push(make_pair(A[i], A[i + 1]));
}
int next(int n) {
while (n > 0) {
if (num.empty())
return -1;
pair<int, int> &sta = num.front();
if (n <= sta.first) {
sta.first -= n;
if (sta.first == 0)
num.pop();
return sta.second;
}
else {
n -= sta.first;
num.pop();
}
}
return -1;
}
};
/**
* Your RLEIterator object will be instantiated and called as such:
* RLEIterator obj = new RLEIterator(A);
* int param_1 = obj.next(n);
*/