RLE Iterator #算法#

原题如下:

(不想看的直接看下面的简单中文解释)
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”.

中文意思:简单地说,就是给定一个序列,如A = [3,8,0,9,2,5],对于偶数i,A[i]表示A[i]出现的个数,比如这个A就表示3个8,0个9,2个5,那么序列A就是序列[8, 8, 8, 5, 5]的RLE(run-length encoding),我们要实现的是一个函数next(int n),表示删掉用RLE初始化的原序列的n个数字(从头开始按顺序删),并返回最后删除的那个元素的值;若数不够删,则返回-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].
    删除序列的两个元素,最后删除的是8,所以返回8;剩下的序列为[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:

  1. 0 <= A.length <= 1000
  2. A.length is an even integer.
  3. 0 <= A[i] <= 10^9
  4. There are at most 1000 calls to RLEIterator.next(int n) per test case.
  5. Each call to RLEIterator.next(int n) will have 1 <= n <= 10^9.

思路:

一开始天真地以为真的要按照RLE计算出原来的序列再进行操作,然后提交之后发现runtime error,原来给出的测试样例的数字会非常大,所以如果转换出原序列,需要的空间自然会非常大,导致资源浪费,甚至空间不够用。仔细一想,这样的RLE转换本来就是为了节省空间的,我又把它转换回去了,自然不是这道题的意思。所以就必须在RLE上面处理了,能想到这里其实就不复杂了。
首先对于RLE序列A,下标为偶数i的项A[i]为其后一项A[i+1]的数量,所以当要删掉其中的n项时,自然就需要跟A[i]比较大小,分三种情况:
(1) A[i] >= n 够减,则v[i] -= n;并返回v[i+1]的值;
(2) A[i] < n 不够减,则n -= v[i];v[i] = 0;并继续检测下一个i;
(3) 循环结束了还是不能找到A[i] >= n,表示数不够,返回-1。

代码:

class RLEIterator {
public:
    RLEIterator(vector<int> A) {
        v = A;
    }

    int next(int n) {
        // 遍历偶数项
        for(int i = 0; i < v.size() - 1; i+=2){
            if(v[i] >= n){
                v[i] -= n;
                return v[i+1];
            }
            else if (v[i] != 0){
                n -= v[i];
                v[i] = 0;
            }
        }
        return -1;
    }
private:
    vector<int> v;
};

改进

以上的方法每次都要从头开始,如果经过多次删除之后前面很多数的个数为0,这样就浪费了前面查询的时间,可以用一个head来跟踪第一个不是0的偶数位置,这样就不用每次都要从头开始,提高效率。代码如下:

class RLEIterator {
public:
    RLEIterator(vector<int> A) {
        v = A;
        head = 0;
    }

    int next(int n) {
        int ret = -1; 
        for(; head < v.size(); head+=2){
            if(v[head] >= n){
                v[head] -= n;
                ret = v[head+1];
                break;
            }
            if(v[head] != 0){
                n -= v[head];
                v[head] = 0;
            }
        }
        // 跳过个数为0的数 
        while(head < v.size() && v[head] == 0) head += 2;
        return ret;
    }
private:
    vector<int> v;
    int head;
};

猜你喜欢

转载自blog.csdn.net/Runner1st/article/details/82634266