查找不在列表中的最小整数


87

我的一位同事使用的一个有趣的采访问题:

假设您得到了一个很长的,未排序的无符号64位整数列表。您将如何找到列表中未出现的最小非负整数?

跟进:现在已经提出了明显的排序解决方案,您可以比O(n log n)更快吗?

跟进:您的算法必须在具有1GB内存的计算机上运行

澄清:该列表位于RAM中,尽管它可能会消耗大量的内存。预先给您列表的大小,例如N。


6
我认为您可以忽略非负部分,看看您如何谈论无符号整数。
2009年

4
这个问题是非常基本的,除非我在IMO基地以外,但是,正如其他人所提到的,还有一些问题要问,或者应该说明一些假设。
詹姆斯·布莱克

8
@paxdiablo:在这种情况下,说O(n)的意义并不大。即使将2 ^ 64位数组存储在Easter Island的粘土板上并由信鸽访问,该算法仍为O(n)。
IJ肯尼迪

6
中途更改内存要求使这成为一个很好的面试问题;-)
克里斯·巴伦斯

1
我认为所有答案都使用相同的一般解决方案(对数组进行排序并找到破坏序列的第一个值)是很有趣的,但是它们都使用了不同的排序。(修改的quicksort,radix排序,...)接受的答案等同于计数排序,该排序丢弃N以上的元素
。– Joren

Answers:


121

如果数据结构可以在适当位置进行突变并支持随机访问,则可以在O(N)时间和O(1)额外空间中进行操作。只需依次遍历数组,并为每个索引将索引处的值写入由value指定的索引,然后将该位置的任何值递归地放置到该位置,并丢弃> N的值即可。然后再次遍历该数组以查找该点其中value与索引不匹配-这是不在数组中的最小值。这样最多可以进行3N比较,并且仅使用一些值的临时空间。

# Pass 1, move every value to the position of its value
for cursor in range(N):
    target = array[cursor]
    while target < N and target != array[target]:
        new_target = array[target]
        array[target] = target
        target = new_target

# Pass 2, find first location where the index doesn't match the value
for cursor in range(N):
    if array[cursor] != cursor:
        return cursor
return N

9
小nitpick。您错过了一个琐碎的案例:当列表为{0,...,N-1}时。在这种情况下,过程1不执行任何操作,而过程2中array [cursor] ==游标用于列表中的所有条目,因此算法不会返回。因此,您最后需要一个“ return N”语句。
亚历克斯

12
您的解决方案会缩小域和范围(目标既是值又是索引)。该范围受可用存储限制为128M个元素,但域大小为2G。如果单个条目的值大于可以分配给数组的条目数,它将失败。如果问题未指定“ very long”,则答案很优雅,即使它破坏了输入。时空权衡在此问题中非常明显,并且在提供的约束下O(N)解决方案可能无法实现。
Pekka 2013年

2
第二遍可以使用二进制搜索而不是线性搜索。
2013年

4
仅当值的范围和索引可比较时,此解决方案才有效。
Dubby 2014年

7
较大的值可以正常工作。较大的值可以忽略,因为它们与不在数组中的最小值没有任何关系。对于您的示例,第一遍将遍历数组,忽略所有由于target <N而引起的值,然后在第二遍的第一次迭代中返回0。
Ants Aasma 2015年

89

这是一个O(N)使用O(N)空间的简单解决方案。我假设我们将输入列表限制为非负数,并且我们要查找列表中未包含的第一个非负数。

  1. 找到列表的长度;可以说是N
  2. 分配一个N布尔数组,初始化为全部false
  3. 对于X列表中的每个数字,如果X小于N,则将X'th数组的元素设置为true
  4. 从索引开始扫描数组0,寻找第一个元素false。如果您false在index处找到第一个I,那么I答案就是。否则(即当所有元素都存在时true)答案是N

实际上,“N布尔数组”可能会被编码为表示为byteint数组的“位图”或“位集” 。通常,这会使用较少的空间(取决于编程语言),并允许false更快地扫描第一个。


这就是算法工作的方式/原因。

假设N列表中的数字不是唯一的,或者其中一个或多个大于N。这意味着该范围内必须至少有一个0 .. N - 1不在列表中的数字。因此,寻找最小遗漏数的问题必须减少到寻找最小遗漏数小于N的问题。这意味着我们无需跟踪大于或等于的数字N...因为它们不会成为答案。

上一段的替代方法是该列表是的数字的排列0 .. N - 1。在这种情况下,第3步将数组的所有元素设置为true,第4步告诉我们第一个“缺失”数字为N


该算法的计算复杂度O(N)具有相对较小的比例常数。它在列表中进行了两次线性遍历,如果已知列表长度以其开头,则仅进行一次遍历。无需表示将整个列表保存在内存中,因此算法的渐近内存使用量正是表示布尔数组的条件;即O(N)

(相比之下,依赖于内存中排序或分区的算法假定您可以在内存中表示整个列表。以提出问题的形式,这将需要O(N)64位字。)


@Jorn评论说第1步到第3步是计数排序的变体。从某种意义上说他是对的,但差异是巨大的:

  • 计数排序需要一个(至少)Xmax - Xmin计数器数组,其中计数器Xmax是列表中的最大数字,而列表Xmin中的最小数字。每个计数器必须能够代表N个状态;即假设二进制表示形式,它必须具有(至少)整数类型的ceiling(log2(N))位。
  • 为了确定数组的大小,计数排序需要首先通过列表来确定XmaxXmin
  • 因此,最坏情况下的最小空间需求是ceiling(log2(N)) * (Xmax - Xmin)位。

相比之下,上述算法仅N在最坏情况和最佳情况下才需要位。

但是,这种分析得出的直觉是,如果算法对列表进行初始遍历以寻找零(并在需要时对列表元素进行计数),则找到零时将不使用任何空间就能给出更快的答案。如果极有可能在列表中找到至少一个零,那么绝对值得这样做。而且这种额外的通过不会改变整体的复杂性。


编辑:我已经更改了算法的描述以使用“布尔数组”,因为人们显然发现我使用位和位图的原始描述令人困惑。


3
@ adi92如果步骤3为您提供了一个将所有位都设置为1的位图,则列表包含从0到N-1的每个值。这意味着列表中最小的非负整数为N。如果列表中未包含0到N-1之间的任何值,则不会设置相应的位。因此,最小的值就是答案。
09年

4
@ adi92在您的示例中,列表将包含300个元素。这意味着,如果有任何“缺失”值,则该值必须小于300。运行该算法,我们将创建一个具有300个插槽的位域,然后重复设置插槽1、2和3中的位,剩下的所有其他插槽-0和4至299-清除。扫描位域时,我们会发现插槽0中的标志清除了,所以我们知道0是答案。
divegeek

4
请注意,这种算法可能无需花些时间就可以更简单地理解:“创建大小为N的布尔数组”等。一旦理解了这一点,从概念上讲,移至按位版本很容易。
乔恩·斯基特

2
提供抽象解决方案时,请使用最简单有效的概念方法,不要过于专业化。您的解决方案大喊大叫使用(抽象的)布尔数组,因此称其为。您可能bool[]通过位图或通过位图实现此数组与常规解决方案无关。
Joren

2
我认为此解决方案可能最好地描述为“使用忽略N之上的元素的计数排序,然后从头开始进行线性搜索来找到第一个缺失的元素”。
Joren

13

由于OP现在已指定原始列表保存在RAM中,并且计算机仅具有1GB的内存,因此,我将不遗余力地预测答案为零。

1GB的RAM意味着列表中最多可以包含134,217,728个数字。但是有2 64 = 18,446,744,073,709,551,616个可能的数字。因此,列表中为零的概率为137,438,953,472中的1。

相反,我今年雷击的几率是70万分之一。而且我被陨石击中的几率约为10万亿分之一。因此,由于我因天体过早死亡而被写在科学期刊上的可能性要比答案不为零高十倍。


11
仅当值均匀分布并随机选择时,您的计算才成立。它们也可能是顺序生成的。
divegeek

1
你是正确的,当然。但我全都在针对常见情况进行优化。:)
巴里·布朗

10
那么,被访者选择这个答案的几率是多少?
2009年

6
问题不是说数字是随机统一选择的。他们是由设置此问题的人选择的。鉴于此,0是在列表中的概率是很大的137438953472大于1,可能是在2比:-) 1更大
ShreevatsaR

8
@Amarghosh该问题的答案也为零。
PeterAllenWebb,2009年

10

正如其他答案中指出的那样,您可以进行排序,然后简单地向上扫描直到找到空白为止。

通过使用修改后的QuickSort,您可以将算法复杂度提高到O(N),并保留O(N)空间,在其中您可以消除那些不是包含间隙的潜在候选对象的分区。

  • 在第一个分区阶段,删除重复项。
  • 分区完成后,查看下部分区中的项目数
  • 该值等于用于创建分区的值吗?
    • 如果是这样,则意味着该间隙位于较高的分区中。
      • 继续快速排序,忽略较低的分区
    • 否则差距在下分区
      • 继续快速排序,忽略更高的分区

这样可以节省大量计算。


那真是太漂亮了。假定您可以在少于线性时间的情况下计算分区的长度,如果将其与分区数组一起存储,则可以完成此操作。它还假定原始列表保存在RAM中。
巴里·布朗

2
如果知道列表的长度,则还可以选择大于len(list)的任何值。根据信鸽原则,任何“漏洞”都必须小于len(list)。
divegeek

1
我不认为这是O(n)...对于一个,我不确定在列表完全排序之前您是否可以删除重复项。其次,尽管您可以保证每次迭代都将一半的搜索空间扔掉(因为您已将其分成中点以下和中点),但是您仍然可以对依赖于n的数据进行多次遍历(取决于n)。
paxdiablo

1
paxdiablo:您可以使用像Stephen C所建议的位图方法来构建仅具有唯一值的新列表。这在O(n)时空中运行。我不确定是否可以做得更好。
尼克

9

为了说明O(N)思考的一个陷阱,这是一种O(N)使用O(1)空间的算法。

for i in [0..2^64):
  if i not in list: return i

print "no 64-bit integers are missing"

1
威尔是正确的。这不是O(n),因为这里实际上有两个循环,但是一个是隐式的。确定一个值是否在列表中是一个O(n)操作,您在for循环中执行了n次。这使它成为O(n ^ 2)。
Nic

6
Nic,请问,它是O(n * N),其中n是列表的大小,N是域的大小(64位整数)。尽管N是一个巨大的数字,但它仍然是一个常数,因此形式上所述问题的复杂度为O(n)。
蚂蚁阿斯玛

1
蚂蚁,我同意这是O(n N),但N不是常数。由于该算法在找到答案后即告完成,因此通过外循环执行的完整迭代次数等于答案,答案本身受列表大小限制。因此,在这种情况下,O(N n)为O(n ^ 2)。
哈里斯·哈里斯(

12
在N个元素的列表中查找数字显然是O(N)。我们这样做2 ^ 64次。虽然很大,但是2 ^ 64是常数。因此,算法为C * O(N),仍为O(N)。
IJ肯尼迪

3
我必须背诵我以前的发言;根据最严格的定义,该运算确实为O(n)。
Nic

8

由于数字都是64位长,我们可以使用 基数排序对它们,即O(n)。对它们进行排序,然后对它们进行扫描,直到找到所需的内容。

如果最小数字为零,则向前扫描直到找到间隙。如果最小数字不为零,则答案为零。


是的,但是对于基数排序,内存需求可能会非常紧张。
2009年

1
基数排序不适用于非常大的数据集。但是分区和基数排序可能有效。
DarthVader

5

对于节省空间的方法,所有值都是不同的,您可以在空间O( k )和时间上做到O( k*log(N)*N )。它节省空间,没有数据移动,所有操作都是基本操作(加减)。

  1. U = N; L=0
  2. 首先将数字空间划分为k区域。像这样:
    • 0->(1/k)*(U-L) + L0->(2/k)*(U-L) + L0->(3/k)*(U-L) + L...0->(U-L) + L
  3. 查找count{i}每个区域中有多少个数字()。(N*k步骤)
  4. 找到第一个h未满的区域()。那意味着count{h} < upper_limit{h}。(k步骤)
  5. 如果h - count{h-1} = 1你有答案
  6. U = count{h}; L = count{h-1}
  7. 转到2

使用散列可以改善这一点(感谢Nic这个想法)。

  1. 相同
  2. 首先将数字空间划分为k区域。像这样:
    • L + (i/k)->L + (i+1/k)*(U-L)
  3. inc count{j} 使用 j = (number - L)/k (if L < number < U)
  4. 查找h其中没有k个元素的第一个区域()
  5. 如果count{h} = 1h是你的答案
  6. U = maximum value in region h L = minimum value in region h

这将在中运行O(log(N)*N)


我真的很喜欢这个答案。读起来有点困难,但是和我读这个问题的时候非常相似。
尼克

也可能在某些时候切换到Stephen C的位图解决方案很可能是因为U-L < k
Egon,2009年

这不是在O(log(N)* N)中运行,而是在O(N)中运行。您的答案是@cdiggins答案的一般化,它以O(N)运行,因为sum(1 / k ** i for i在范围内(ceil(log_k(n))))<=
2。– Lapinot

在每次迭代中,您经历O(N)个数字,总共需要O(log_k(N))次迭代。因此,O(log_k(N)* N)== O(log(N)* N)。原始数字未排序/存储,您需要仔细检查所有数字。
伊贡

但是,如果将原始列表划分为k个区域(大小为n / k),则选择第一个未满的区域。因此,在下一次迭代中,您只需要考虑所选区域并将其划分为k个新区域(大小为n / k ** 2)等。实际上,您每次都不必在整个列表上进行迭代(否则分区的意义是什么) ?)。
Lapinot

3

我将对它们进行排序,然后遍历序列,直到找到一个间隙(包括零与第一个数字之间的起始间隙)。

在算法方面,可以这样做:

def smallest_not_in_list(list):
    sort(list)
    if list[0] != 0:
        return 0
    for i = 1 to list.last:
        if list[i] != list[i-1] + 1:
            return list[i-1] + 1
    if list[list.last] == 2^64 - 1:
        assert ("No gaps")
    return list[list.last] + 1

当然,如果您的内存比CPU占用的内存大得多,则可以创建所有可能的64位值的位掩码,并只为列表中的每个数字设置位。然后在该位掩码中查找第一个0位。就时间而言,这变成了O(n)操作,但是就内存需求而言,这确实是非常昂贵的:-)

我怀疑您是否可以改善O(n),因为我看不到这样做不会涉及至少一次查看每个数字的方法。

用于该算法的算法如下:

def smallest_not_in_list(list):
    bitmask = mask_make(2^64) // might take a while :-)
    mask_clear_all (bitmask)
    for i = 1 to list.last:
        mask_set (bitmask, list[i])
    for i = 0 to 2^64 - 1:
        if mask_is_clear (bitmask, i):
            return i
    assert ("No gaps")

根据描述,它似乎在第一个元素之前排除了0,因为它是列表中最小的元素。但是,这是我做的一个假设,我可能是错的。
詹姆斯·布莱克

我的想法是,如果排序的序列为4,5,6,则0将是列表中最小的序列。
paxdiablo

我希望2、3、5的答案应该是4,但是,我可能是错的。
詹姆斯·布莱克

OP应该回答的问题。搜索空间是“所有64位无符号整数”还是“列表中最低与最高之间的所有数字”?
paxdiablo

我同意,在最坏的情况下,您至少必须查看一次,除非它可能已经在二叉树中排序过。
詹姆斯·布莱克2009年


1

您可以在O(n)时间和O(1)的额外空间中执行此操作,尽管隐藏因素很大。这不是解决问题的实用方法,但是仍然很有趣。

对于每个无符号的64位整数(按升序排列),请遍历列表,直到找到目标整数或到达列表末尾为止。如果到达列表的末尾,则目标整数是不在列表中的最小整数。如果到达64位整数的末尾,则列表中将包含每个64位整数。

这是一个Python函数:

def smallest_missing_uint64(source_list):
    the_answer = None

    target = 0L
    while target < 2L**64:

        target_found = False
        for item in source_list:
            if item == target:
                target_found = True

        if not target_found and the_answer is None:
            the_answer = target

        target += 1L

    return the_answer

故意将该函数保持为O(n)无效。特别要注意的是,即使找到答案,该函数仍会继续检查目标整数。如果找到答案后立即返回该函数,则外循环运行的次数将受答案的大小限制,该大小受n限制。该更改将使运行时间为O(n ^ 2),即使它要快得多。


真正。在实践中,这个问题使O(1)空间和O(n)时间的某些算法在实践中失败的后果令人震惊。
PeterAllenWebb

1

感谢egon,swilden和Stephen C的启发。首先,我们知道目标值的界限,因为它不能大于列表的大小。同样,一个1GB的列表最多可以包含134217728(128 * 2 ^ 20)个64位整数。

散列部分
我建议使用散列来大大减少我们的搜索空间。首先,平方根为列表的大小。对于1GB的列表,则为N = 11,586。设置大小为N的整数数组。遍历列表,并将找到的每个数字的平方根*作为哈希。在哈希表中,增加该哈希的计数器。接下来,遍历哈希表。您发现的第一个不等于最大大小的存储桶定义了新的搜索空间。

位图部分
现在,设置一个与新搜索空间大小相等的常规位图,然后再次遍历源列表,在搜索空间中找到每个数字时填写位图。完成后,位图中的第一个未设置位将为您提供答案。

这将在O(n)时间和O(sqrt(n))空间中完成。

(*您可以使用移位之类的方法来更有效地执行此操作,并相应地更改存储桶的数量和大小。)


1
我喜欢将搜索空间划分为Root-N存储桶以减少内存占用的想法,但是列表中的重复项会破坏此方法。我确实想知道它是否可以解决。
2009年

没错,我忽略了考虑重复的条目。我不确定是否可以解决。
尼克

1

好吧,如果数字列表中只有一个缺失的数字,找到缺失数字的最简单方法是对序列求和,然后减去列表中的每个值。最终值是缺少的数字。


是的 这是另一个经典的面试问题。
PeterAllenWebb

1
将列表中的数字与XOR,将范围中的数字与XOR以及结果与XOR的比这更容易。
John Kurlak 2014年

1
 int i = 0;
            while ( i < Array.Length)
            {

                if (Array[i] == i + 1)
                {
                    i++;
                }

                if (i < Array.Length)
                {
                    if (Array[i] <= Array.Length)
                    {//SWap

                        int temp = Array[i];
                        int AnoTemp = Array[temp - 1];
                        Array[temp - 1] = temp;
                        Array[i] = AnoTemp;

                    }
                    else
                       i++;



                }
            }

            for (int j = 0; j < Array.Length; j++)
            {
                if (Array[j] > Array.Length)
                {
                    Console.WriteLine(j + 1);
                    j = Array.Length;
                }
                else
                    if (j == Array.Length - 1)
                        Console.WriteLine("Not Found !!");

            }
        }

1

我们可以使用哈希表来保存数字。完成所有数字后,从0开始运行一个计数器,直到找到最低数为止。合理的哈希值将在固定时间内进行哈希和存储,并在固定时间内进行检索。

for every i in X         // One scan Θ(1)
   hashtable.put(i, i);  // O(1)

low = 0;

while (hashtable.get(i) <> null)   // at most n+1 times
   low++;

print low;

最坏的情况是n数组中有元素,而{0, 1, ... n-1}在这种情况下,答案将n保持不变O(n)


1

这是我用Java写的答案:

基本思想:1-遍历数组,丢弃重复的正数,零数和负数,同时对其余的数求和,获得最大的正数,并将唯一的正数保留在Map中。

2-计算总和为max *(max + 1)/ 2。

3-找到在步骤1和2计算得出的总和之间的差

4-再次从1循环到[sum sum,max]的最小值,并返回步骤1中未填充的映射中未包含的第一个数字。

public static int solution(int[] A) {
    if (A == null || A.length == 0) {
        throw new IllegalArgumentException();
    }

    int sum = 0;
    Map<Integer, Boolean> uniqueNumbers = new HashMap<Integer, Boolean>();
    int max = A[0];
    for (int i = 0; i < A.length; i++) {
        if(A[i] < 0) {
            continue;
        }
        if(uniqueNumbers.get(A[i]) != null) {
            continue;
        }
        if (A[i] > max) {
            max = A[i];
        }
        uniqueNumbers.put(A[i], true);
        sum += A[i];
    }
    int completeSum = (max * (max + 1)) /  2;
    for(int j = 1; j <= Math.min((completeSum - sum), max); j++) {
        if(uniqueNumbers.get(j) == null) { //O(1)
            return j;
        }
    }
    //All negative case
    if(uniqueNumbers.isEmpty()) {
        return 1;
    }
    return 0;
}

0

正如Stephen C聪明地指出的那样,答案必须是小于数组长度的数字。然后,我将通过二进制搜索找到答案。这样可以优化最坏的情况(因此,面试官无法在“假设的情况”下抓住您)。在采访中,一定要指出您正在这样做,以针对最坏的情况进行优化。

使用二进制搜索的方法是从数组的每个元素中减去您要查找的数字,并检查是否为负数。


0

我喜欢“零猜测”方法。如果数字是随机的,则很有可能为零。如果“检查者”设置了非随机列表,则添加一个并再次猜测:

LowNum=0
i=0
do forever {
  if i == N then leave /* Processed entire array */
  if array[i] == LowNum {
     LowNum++
     i=0
     }
   else {
     i++
   }
}
display LowNum

最坏的情况是n * N,n = N,但实际上n很可能是一个很小的数字(例如1)


0

我不确定是否有这个问题。但是如果列表1,2,3,5,6的缺失数为4,则可以通过以下方式在O(n)中找到缺失数:(n + 2)(n + 1)/ 2-(n + 1)n / 2

编辑:对不起,我想昨天晚上我想得太快了。无论如何,第二部分实际上应该由sum(list)代替,这是O(n)的所在。该公式揭示了其背后的想法:对于n个连续整数,总和应为(n + 1)* n / 2。如果缺少数字,则总和等于(n + 1)个连续整数的总和减去数字。

感谢您指出我正在考虑一些中间问题。


1
我乍看之下不知道如何运作。在您的情况下,n = 5并且公式将固定,无论其中缺少多少个数字。
sisve

西蒙:您现在可以根据我的编辑删除不赞成票吗?
Codism

0

干得好蚂蚁Aasma!我考虑了大约15分钟的答案,然后独立提出了与您的想法类似的答案:

#define SWAP(x,y) { numerictype_t tmp = x; x = y; y = tmp; }
int minNonNegativeNotInArr (numerictype_t * a, size_t n) {
    int m = n;
    for (int i = 0; i < m;) {
        if (a[i] >= m || a[i] < i || a[i] == a[a[i]]) {
            m--;
            SWAP (a[i], a[m]);
            continue;
        }
        if (a[i] > i) {
            SWAP (a[i], a[a[i]]);
            continue;
        }
        i++;
    }
    return m;
}

m表示“给定我对前i个输入的了解,并假设在m-1处输入之前的值,当前最大可能输出”。

仅当(a [i],...,a [m-1])是值(i,...,m-1)的排列时,才会返回m的值。因此,如果a [i]> = m或a [i] <i或a [i] == a [a [i]],我们知道m是错误的输出,并且必须至少低一个元素。因此,递减m并将a [i]与a [m]交换就可以递归了。

如果这不是真的,而是a [i]> i,那么知道a [i]!= a [a [i]],我们知道将a [i]与a [a [i]]交换会增加元素数量在自己的位置。

否则,a [i]必须等于i,在这种情况下,我们可以知道已知直到该索引(包括该索引)的所有值都等于它们的索引,从而可以递增i。

这不能进入无限循环的证明留给读者练习。:)


0

Ants回答中的Dafny片段显示了原位算法可能失败的原因。该requires先决条件描述了每个项目的值不能超越数组的边界。

method AntsAasma(A: array<int>) returns (M: int)
  requires A != null && forall N :: 0 <= N < A.Length ==> 0 <= A[N] < A.Length;
  modifies A; 
{
  // Pass 1, move every value to the position of its value
  var N := A.Length;
  var cursor := 0;
  while (cursor < N)
  {
    var target := A[cursor];
    while (0 <= target < N && target != A[target])
    {
        var new_target := A[target];
        A[target] := target;
        target := new_target;
    }
    cursor := cursor + 1;
  }

  // Pass 2, find first location where the index doesn't match the value
  cursor := 0;
  while (cursor < N)
  {
    if (A[cursor] != cursor)
    {
      return cursor;
    }
    cursor := cursor + 1;
  }
  return N;
}

将带有和不带有forall ...子句的代码粘贴到验证器中,以查看验证错误。第二个错误是验证程序无法为Pass 1循环建立终止条件的结果。证明这一点的人是对工具更了解的人。


0

这是Java中的一个答案,它不会修改输入,而是使用O(N)时间和N位加上少量的恒定内存开销(其中N是列表的大小):

int smallestMissingValue(List<Integer> values) {
    BitSet bitset = new BitSet(values.size() + 1);
    for (int i : values) {
        if (i >= 0 && i <= values.size()) {
            bitset.set(i);
        }
    }
    return bitset.nextClearBit(0);
}

0
def solution(A):

index = 0
target = []
A = [x for x in A if x >=0]

if len(A) ==0:
    return 1

maxi = max(A)
if maxi <= len(A):
    maxi = len(A)

target = ['X' for x in range(maxi+1)]
for number in A:
    target[number]= number

count = 1
while count < maxi+1:
    if target[count] == 'X':
        return count
    count +=1
return target[count-1] + 1

得到了上述解决方案的100%。


0

1)过滤负数和零

2)排序/不同

3)访问数组

复杂度:O(N)或O(N * log(N))

使用Java8

public int solution(int[] A) {
            int result = 1;
    boolean found = false;
    A = Arrays.stream(A).filter(x -> x > 0).sorted().distinct().toArray();
    //System.out.println(Arrays.toString(A));
    for (int i = 0; i < A.length; i++) {
        result = i + 1;
        if (result != A[i]) {
            found = true;
            break;
        }
    }
    if (!found && result == A.length) {
        //result is larger than max element in array
        result++;
    }
    return result;
}

0

可以使用unordered_set存储所有正数,然后我们可以从1迭代到unordered_set的长度,并查看没有出现的第一个数字。

int firstMissingPositive(vector<int>& nums) {

    unordered_set<int> fre;
    // storing each positive number in a hash.
    for(int i = 0; i < nums.size(); i +=1)
    {
        if(nums[i] > 0)
            fre.insert(nums[i]);
     }

    int i = 1;
    // Iterating from 1 to size of the set and checking 
    // for the occurrence of 'i'

    for(auto it = fre.begin(); it != fre.end(); ++it)
    {
        if(fre.find(i) == fre.end())
            return i;
        i +=1;
    }

    return i;
}

0

通过基本的javascript解决方案

var a = [1, 3, 6, 4, 1, 2];

function findSmallest(a) {
var m = 0;
  for(i=1;i<=a.length;i++) {
    j=0;m=1;
    while(j < a.length) {
      if(i === a[j]) {
        m++;
      }
      j++;
    }
    if(m === 1) {
      return i;
    }
  }
}

console.log(findSmallest(a))

希望这对某人有帮助。


0

使用python它不是最有效的,但是是正确的

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import datetime

# write your code in Python 3.6

def solution(A):
    MIN = 0
    MAX = 1000000
    possible_results = range(MIN, MAX)

    for i in possible_results:
        next_value = (i + 1)
        if next_value not in A:
            return next_value
    return 1

test_case_0 = [2, 2, 2]
test_case_1 = [1, 3, 44, 55, 6, 0, 3, 8]
test_case_2 = [-1, -22]
test_case_3 = [x for x in range(-10000, 10000)]
test_case_4 = [x for x in range(0, 100)] + [x for x in range(102, 200)]
test_case_5 = [4, 5, 6]
print("---")
a = datetime.datetime.now()
print(solution(test_case_0))
print(solution(test_case_1))
print(solution(test_case_2))
print(solution(test_case_3))
print(solution(test_case_4))
print(solution(test_case_5))

0
def solution(A):
    A.sort()
    j = 1
    for i, elem in enumerate(A):
        if j < elem:
            break
        elif j == elem:
            j += 1
            continue
        else:
            continue
    return j

0

这可以帮助:

0- A is [5, 3, 2, 7];
1- Define B With Length = A.Length;                            (O(1))
2- initialize B Cells With 1;                                  (O(n))
3- For Each Item In A:
        if (B.Length <= item) then B[Item] = -1                (O(n))
4- The answer is smallest index in B such that B[index] != -1  (O(n))

这与斯蒂芬·C的答案不同吗?怎么样?
灰胡子
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.