在无限的整数序列中找到重复的最佳方法是什么?
即。如果在无限序列中数字'5'出现两次,那么我们将第一次返回'false'而第二次返回'true'。
最后我们需要的是一个函数,如果整数出现在前面,则返回'true',如果函数第一次收到整数,则返回'false'。
如果有两个解决方案,一个是空间方式,第二个是时间方式,那么两个都提到。 我会在答案中写下我的解决方案,但我认为这不是最佳解决方案。
编辑:请不要假设琐碎的情况(即没有重复,不断上升的序列)。我感兴趣的是如何减少非平凡情况的空间复杂性(重复的随机数)。
答案 0 :(得分:1)
我会使用以下方法:
使用哈希表作为数据结构。对于读取的每个数字,将其存储在数据结构中。如果在您发现重复之前已经存储了它。
如果n是从开始到重复的序列中元素的数量,那么这只需要O(n)时间和空间。时间复杂度是最佳的,因为您需要至少读取输入序列的元素直到重复点。
我们说话的序列有多长(在重复发生之前)?重复甚至可以保证吗?对于极端情况,空间复杂性可能会成为问题。但要改进它,您可能需要了解更多关于序列的结构信息。
更新:如果序列如你所说很长很少重复并且你必须减少空间要求,那么你可以(给出足够的序列结构信息)能够减少空间成本。
作为一个例子:假设您知道您的无限序列通常倾向于返回符合当前目标最小 - 最大数字范围内的数字。然后,您最终将具有已包含在序列中的整个间隔。在这种情况下,您可以通过存储此类间隔而不是其中包含的所有元素来节省空间。
答案 1 :(得分:1)
int值的BitSet(2 ^ 32个数字)将消耗512Mb。如果BitSets不经常分配,足够快并且mem可用,则可能没问题。
替代方案是compressed BitSets,最适合稀疏的BitSet。
答案 2 :(得分:1)
实际上,如果最大值的数量是无限的,则可以对单色位图使用任何无损压缩算法。如果你想象一个像素数量至少与可能值的数量一样多的正方形,你可以将每个值映射到一个像素(有几个像素备用)。然后,您可以将白色表示为出现的像素,将其他像素表示为黑色,如果空间非常宝贵,则可以使用任何压缩算法(这肯定是已经研究过的问题)
您还可以存储块。最坏的情况在空间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
}
此代码如下:它存储块列表。对于您添加的每个数字,它会迭代列表,其中包含出现的数字块和未出现的数字块。让我用一个例子来说明;我将添加[)来说明块中的哪些数字,包含第一个数字,最后一个不是。在伪代码中,它被布尔appeared
替换。例如,如果你得到5,9,6,8,7(按此顺序),你将在每个函数后有以下序列:
[5,6)
[5,6),[9,10)
[5,7),[9,10)
[5,7),[8,10)
[5,10)
在最后一个值中,您只保留5个数字的块,只有2个。
答案 3 :(得分:0)
返回TRUE
如果序列是无限的,则会重复每个可想到的模式。
如果您想知道的是序列中的第一个位置,那么重复的数字是另一个问题,但是您的问题与您的示例之间存在一些差异。
答案 4 :(得分:0)
嗯,似乎很明显,在任何解决方案中我们都需要保存已经出现的数字,因此在空间方面我们总是具有O(N)的最坏情况,其中N 为了保存已经出现的数字,我会使用哈希表,然后在每次收到新号码时检查它。