查找第一个可用名称的高效算法

时间:2011-01-14 21:41:15

标签: arrays algorithm data-structures

我有一个包含项目名称的数组。 我想给用户提供创建项目的选项而不指定他们的名字,所以我的程序必须提供一个唯一的默认名称,如“Item 1”。

挑战是名称必须是唯一的,所以我必须检查所有数组的默认名称,如果有一个具有相同名称的项目,我必须将名称更改为“项目2”,所以直到找到可用的名字。

明显的解决方案就是这样:

String name = "Item ";
for (int i = 0; !isAvailable(name + i) ; i++);

我的算法问题是它运行在O(N ^ 2)。

我想知道是否有一种已知的(或新的)更有效的算法来解决这种情况。

换句话说,我的问题是:是否有任何算法可以找到在给定数组中不存在的第一个大于零的数字,并且运行的数量少于N ^ 2?

7 个答案:

答案 0 :(得分:4)

你当然可以在O(N)时间内完成,N是数组中的项目数:

  • “第1项”,“第2项”之一,......“项目N + 1”必须是免费的,因此请创建一个N + 1标志数组。
  • 遍历项目,如果形式为“项目k”,则为每个名称,其中0 <&lt; k&lt; = N + 1,设置该标志。
  • 扫描标志数组以获取第一个清除标志。

额外的内存要求是N + 1位,这肯定胜过实际存储所有N个名称的任何数据结构。

答案 1 :(得分:3)

是的,有。

首先对数组进行排序。然后运行它并返回其值不等于其索引的第一个元素(加1)。排序是O(n log n),最后一步是O(n),所以整个事情是O(n log n)。

如果将所有项目放入哈希表中,则可以在O(n)中以某些空间为代价,并在创建新项目时执行额外的O(1)步骤。由于需要访问每个元素,因此O(n)显然是最优的。

我有兴趣看看是否有O(n)方法来执行此操作,没有使用任何“持久”数据结构(如哈希表)。 (并假设无界整数,否则桶排序可以用作O(n)排序算法。)

答案 2 :(得分:1)

答案 3 :(得分:1)

将所有现有名称插入哈希表。重复你的循环,但使isAvailable检查哈希表。假设一个合适的哈希,它是O(nh),其中h是评估哈希的成本。

答案 4 :(得分:1)

您可以尝试执行以下操作:

第一

  • 遍历列表,并获取所有编号的项目,这是复杂性N
  • 对于每个编号的项目,将项目放在树中(在C ++中:std :: map),这是复杂性日志(N)

所以现在你已经建立了一个使用了数字的地图,复杂度为“N x log(N)”

接下来,迭代到树,一旦看到“洞”,请使用数字。 最坏的情况是复杂性N。

总的来说,复杂度为N x log(N)+ N,或简化为:N log(N)。

答案 5 :(得分:0)

如果只有一个用户访问此阵列,为什么不使用nanoseconds的号码?当然,这假设用户比计算机慢得多,这似乎是一个安全的假设。

这样,您确定唯一名称的成本为O(1)。

答案 6 :(得分:0)

对数时间方法,假设您永远不会通过删除项目留下“漏洞”:

// Inverse binary search for the last one.
int upperBound = 1;
while(isInUse(upperBound)) upperBound *= 2;

// Standard binary search for the end once we have a ballpark.
int lowerBound = upperBound / 2;
while(lowerBound < upperBound - 1)
{
    int midpoint = (lowerBound + upperBound) / 2;
    if (isInUse(midpoint))
        lowerBound = midpoint;
    else
        upperBound = midpoint;
}
return upperBound;

如果可以通过删除释放项目编号,除非您还保留“免费列表”并从中进行选择,否则任何线性搜索都不会有效。