Algorithm 正数流中任何时间点的最小缺失数
我们正在处理一个正整数流。在任何时候,我们都可以被问到一个问题,这个问题的答案是我们尚未见过的最小正数 可以假设有两个APIAlgorithm 正数流中任何时间点的最小缺失数,algorithm,data-structures,Algorithm,Data Structures,我们正在处理一个正整数流。在任何时候,我们都可以被问到一个问题,这个问题的答案是我们尚未见过的最小正数 可以假设有两个API void processNext(int val) int getSmallestNotSeen() 我们可以假设这些数字在[1,10^6]的范围内。让这个范围为N 这是我的解决办法 让我们看一个大小为10^6的数组每当调用processNext(val)时,我们将数组[val]标记为1。我们在这个数组上创建一个和段树。这将是段树中的点更新每当调用getSmallest
void processNext(int val)
int getSmallestNotSeen()
我们可以假设这些数字在[1,10^6]的范围内。让这个范围为N
这是我的解决办法
让我们看一个大小为10^6的数组每当调用processNext(val)时,我们将数组[val]标记为1。我们在这个数组上创建一个和段树。这将是段树中的点更新
每当调用getSmallestNotSeen()时,我都会找到最小的索引j,使得sum[1..j]小于j。我使用二进制搜索找到j。
processNext(val)->O(1)
getSmallestNotSeen()->O((logN)^2) 我在想,如果有更好的办法。或者可以改进上述解决方案。制作id->node(双链接列表的节点)的映射,并初始化10^6个节点,每个节点指向其邻居。将min初始化为1 processNext(val):检查节点是否存在。如果有,请删除它,并将它的邻居彼此指向对方。如果删除的节点没有左邻居(即最小的节点),请将最小节点更新为右邻居 getSmallestNotSeen():返回最小值 预处理是线性时间和线性内存。之后的一切都是常数时间。您的解决方案需要O(N)个空间来保存数组和求和段树,并需要O(N)个时间来初始化它们;然后对这两个查询执行O(1)和O(log²N)。很明显,如果有很多查询,那么从长远来看,要跟踪到目前为止“看到”了哪些数字,没有比O(N)空间更好的了 但是,不同的数据结构可以提高查询时间。这里有三个想法:
自平衡二叉搜索树 初始化树以包含从1到N的每个数字;这可以在O(N)时间内完成,方法是从叶子向上建树;叶子有所有的奇数,然后它们被所有2模4的数连接起来,然后那些被4模8的数连接起来,依此类推。这棵树占了O(N)的空间
通过在O(log N)时间内从树中删除数字来实现processNext
通过在O(logn)时间内查找最左边的节点来实现getSmallestNotSeen
getSmallestNotSeen
,这是一种改进,但是如果很少调用getSmallestNotSeen
,那么您的解决方案会更好,因为它在O(1)而不是O(log N)中处理下一步
双链表 初始化一个按顺序包含数字1到N的双链接列表,并创建一个大小为N的数组,其中包含指向每个节点的指针。这需要O(N)个空间,并且在O(N)个时间内完成。初始化包含缓存最小值为1的变量
通过在数组中查找相应的列表节点并将其从列表中删除来实现。如果删除的节点没有前置节点,则将缓存的最小值更新为后续节点所保留的值。这是O(1)次processNext
通过在O(1)时间内返回缓存的最小值来实现getSmallestNotSeen
散列集 其他解决方案的时间要求在很大程度上取决于它们的初始化阶段,这需要O(N)个时间。另一方面,初始化空哈希集是O(1)。和前面一样,我们还初始化了一个变量,该变量的当前最小值为1
通过在集合中插入数字来实现,以O(1)摊销时间为单位processNext
通过递增当前最小值直到它不再在集合中,更新当前最小值,然后返回它。哈希集上的成员资格测试为O(1),所有查询的增量数量受调用getSmallestNotSeen
的次数限制,因此这也是O(1)摊销时间processNext
我认为证明O(min(Q,N))空间是渐近最优的应该很简单,所以哈希集是最好的选择。在O(1)摊销时间内,将哈希集与当前最小变量相结合以执行
getSmallestNotSeen
,这要归功于
bool array[10^6] = {false, false, ... }
int min = 1
void processNext(int val) {
array[val] = true // A
while (array[min]) // B
min++ // C
}
int getSmallestNotSeen() {
return min
}
时间复杂性:
- 下一步处理:摊销
O(1)
- getSmallestNotSeen:
O(1)
processNext
次k
,并且n
是min
中存储的最高值(可在getSmallestNotSeen
中返回),则:
- 行
将精确执行A
次k
- 行
将精确执行B
次,并且k+n
- 行
将被精确执行C
n次
n
永远不会大于k
,因为min
要达到n
,数组中需要有一个连续的n
true
,数组中总共只能有k
true
。因此,行B
最多可以执行2*k
次,行C
最多可以执行k
次
空间复杂性:
可以使用HashMap代替数组,而无需对
HashMap<int,bool> map
int min = 1
void processNext(int val) {
if (val < min)
return
map.put(val, true)
while (map.get(min) = true)
map.remove(min)
min++
}
int getSmallestNotSeen() {
return min
}