我们有一组对象,我们称之为玩家。我们只能通过随机顺序遍历此组,例如没有Players[0]
这样的东西。
每位玩家都有一个ID
唯一ID < len(Players)
。玩家可以添加到组中并移除。当玩家被移除后,它将释放他的ID
,如果玩家被添加,它将获得ID
。
如果我们想要向玩家添加新播放器,我们必须生成新的唯一ID
。在O(1)空间中生成此类ID
的最快方法是什么?
答案 0 :(得分:6)
O(n log n)可以通过二分查找。以a = 0和b = n开头。不变量是在区间[a,b)中存在空闲id。重复以下步骤,直到b - a = 1:令m = a + floor((b - a)/ 2),计算[a,m]和[m,b)中的id数。如果[a,m)小于m - a id,则设置b = m。否则,设置a = m。
答案 1 :(得分:1)
我认为您可以使用队列将已释放的ID排入队列。一旦消耗掉尽可能高的ID,就将队列排队以获得免费ID。这将需要O(1)。
int highestIndex = 0;
添加玩家
if (highestIndex < len(Players)-1){
ID = ++highestIndex();
}
else if (!queue.isEmpty()){
ID = queue.dequeue();
} else{
// max players reached
}
删除玩家
queue.enqueue(ID);
答案 2 :(得分:0)
基于首先提出的具有固定最大玩家数量的问题:
1)从技术上讲,玩家的大小是O(1)。构建一个1000个插槽的漏洞阵列,每个玩家一个,其中TRUE表示“已分配ID”。当玩家死亡时,将其位的ID设置为false。当新玩家到达时,在位阵列中搜索“假”位;将该ID分配给播放器并设置该位。
时间是O(1),也是一个很大的常数。
根据与任意N名球员一起修改的问题:
2)扩展霍尔的想法:保持一个小的固定大小的数组k&lt; &LT; N作为免费ID的缓存。以TMJ描述的方式使用它。 [TMJ删除了他的回答:它实际上说,“保留一堆未使用的ID,弹出一个未使用的ID,推送新死的ID”]如果在需要新ID时缓存为空,请应用Holzer的方案(甚至可以重新填充执行Holzer方案时的小阵列)。 [Sheesh,Holzer也删除了他的答案,它说“按顺序尝试每个ID并搜索集合;如果没有人拥有该ID,请使用它”(O(N ^ 2)]如果玩家的数量或多或少地到达稳定状态,这将非常快,因为统计上固定大小数组中总会有一些值。
你可以将TMJ的想法与Per的想法结合起来,但你不能在Per扫描期间重新填充数组,只能使用死的玩家ID。
答案 3 :(得分:0)
保留一个布尔数组。在此数组上构造二叉树,使得叶子是数组中的初始值,对于项目i,i + 1,父项是它们的逻辑AND(这意味着其中一个是0)。当你想插入从根向下遍历树以找到第一个空槽(当一个孩子为0时继续向左)。这给出了O(log(n))中的第一个空槽。如果取每个sqrt(n)位组并形成AND父级,则可以得到O(log(log(n))。
答案 4 :(得分:0)
您可以将玩家置于(循环)链接列表中。删除播放器会将其从链中删除,并将其插入另一个列表(“免费”列表)。分配玩家将从“免费”列表中删除(随机)一个并将其插入“活动”列表。
更新: 由于阵列是固定的,你可以使用水印分隔分配给自由球员:
瞧!
答案 5 :(得分:-1)
你的问题是不正确的。答案是:
ID(newPlayer) = 1000
(您没有要求新玩家ID
必须小于1000。)
更严重的是,自O(1000) == O(1)
以来,你可以创建一个id_seen[1000]
数组,标记你目前所见的所有ID
,而不是选择一个你没见过的数组。
为了让您的问题变得有趣,您必须仔细制定,例如: “有N
个玩家ID
s&lt; K
。您只能以未知顺序遍历该集合。使用ID < K
添加O(1)
的新玩家空间。“
一个(低效)答案:选择随机数X < K
。遍历集合。如果您看到有ID == X
的玩家,请重新启动。如果不这样做,请将其用作新的ID
。
评估此算法对给定N
和K
的效率是留给读者的练习; - )