LeetCode 900. RLE 迭代器(模拟/二分查找)

1. 题目

编写一个遍历游程编码序列的迭代器。

迭代器由 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

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/rle-iterator
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2. 解题

2.1 直接模拟

class RLEIterator {
    
    
	vector<int> arr;
	vector<int> count;
	int idx = 0;
	int val;
public:
    RLEIterator(vector<int>& A) {
    
    
    	int n = A.size();
    	arr.resize(n/2);
    	count.resize(n/2);
    	for(int i = 1; i < A.size(); i += 2)
    	{
    
    
    		count[i/2] = A[i-1];//每个数字的个数
    		arr[i/2] = A[i];//数字
    	}
    }
    
    int next(int n) {
    
    
    	val = -1;
    	while(idx < count.size() && n > 0)
    	{
    
    
    		if(count[idx] > n)//个数多
    		{
    
    
    			count[idx] -= n;//当前数字个数减去n
    			return arr[idx];
    		}
    		else//个数不够 或者 刚好
    		{
    
    
    			n -= count[idx];//还差几个 n 
    			if(n == 0)
    				val = arr[idx];
    			idx++;//移动到下一个数
    		}
    	}
    	return val;
    }
};

12 ms 8.2 MB

2.2 二分查找

  • 记录前缀和个数(非减序列),二分查找历史第多少个(n也全部加起来)
class RLEIterator {
    
    
	vector<int> arr;
	vector<long long> count;
	long long totalcount = 0;
public:
    RLEIterator(vector<int>& A) {
    
    
    	for(int i = 1; i < A.size(); i += 2)
    	{
    
    
    		if(A[i-1] == 0)//数量为0,跳过 
    			continue;
    		totalcount += A[i-1];//前缀个数
    		count.push_back(totalcount);
    		arr.push_back(A[i]);
    	}
    	totalcount = 0;//重置
    }
    
    int next(int n) {
    
    
    	totalcount += n; // 二分查找大于等于 totalcount 的第一个元素
    	int l = 0, r = arr.size()-1, mid;
    	while(l <= r)
    	{
    
    
    		mid = l+((r-l)>>1);
    		if(count[mid] < totalcount)
    			l = mid+1;
    		else
    		{
    
    
    			if(mid == 0 || count[mid-1] < totalcount)
    				return arr[mid];
    			else
    				r = mid-1;
    		}
    	}
    	return -1;
    }
};

16 ms 8.5 MB


我的CSDN博客地址 https://michael.blog.csdn.net/

长按或扫码关注我的公众号(Michael阿明),一起加油、一起学习进步!
Michael阿明

猜你喜欢

转载自blog.csdn.net/qq_21201267/article/details/108658180