实际上,如果值的最大数量是无限的,您可以对单色位图使用任何无损压缩算法。如果您想象一个正方形的像素数至少与可能值的数量一样多,您可以将每个值映射到一个像素(有一些备用)。然后,您可以将白色表示为出现的像素,将黑色表示为其他像素,如果空间非常宝贵,则可以使用任何压缩算法(这当然是一个已经研究过的问题)
您还可以存储块。最坏的情况在空间 O(n) 中是相同的,但对于最坏的情况,您需要出现的数字在它们之间恰好有 1。一旦出现更多数字,存储空间就会减少:我将编写伪代码并使用 List,但您始终可以使用不同的结构
List changes // global
boolean addNumber(int number):
boolean appeared = false
it = changes.begin()
while it.hasNext():
if it.get() < number:
appeared != appeared
it = it.next()
else if it.get() == number:
if !appeared: return true
if it.next().get() == number + 1
it.next().remove() // Join 2 blocks
else
it.insertAfter(number + 1) // Insert split and create 2 blocks
it.remove()
return false
else: // it.get() > number
if appeared: return true
it.insertBefore(number)
if it.get() == number + 1:
it.remove() // Extend next block
else:
it.insertBefore(number + 1)
}
return false
}
这段代码如下:它存储了一个块列表。对于您添加的每个数字,它会遍历存储出现的数字块和未出现的数字的列表。让我用一个例子来说明;我将添加 [) 来说明块中的哪些数字,包含第一个数字,最后一个不包含。在伪代码中它被替换为 boolean appeared
。例如,如果您得到 5、9、6、8、7(按此顺序),您将在每个函数之后有以下序列:
[5,6)
[5,6),[9,10)
[5,7),[9,10)
[5,7),[8,10)
[5,10)
在最后一个值中,您保留一个只有 2 个的 5 个数字块。