缺少整数变化 - 需要O(n)解决方案

qiu*_*bit 20 algorithm

问题来自于Codility编程训练,它听起来如下:我们有一个数组(A []​​),其中n(范围从1到100,000)元素,这些是我们的参数.数组的元素是从-2,147,483,648到2,147,483,647的整数,我们需要找到数组中不存在的最小正整数.当然,这可以在O(n*log n)中轻松完成,方法是将它们全部排序并遍历排序的数组,查找缺少的正数(最后一个操作在我的解决方案中具有O(n)最差的时间复杂度).但根据Codility的说法,这个整体问题可以在O(n)中完成,我看不出有任何办法可以做到这一点.有人可以提供一些技巧让我不被卡住吗?

PS这是一个链接,详细描述了我不允许复制的问题 - https://codility.com/c/intro/demo35UEXH-EAT

Gas*_*ssa 41

根据鸽子原理,数字1,2,...,n + 1中的至少一个不在阵列中.让我们创建一个b大小为n + 1 的布尔数组来存储这些数字是否存在.

现在,我们处理输入数组.如果我们找到从1到n + 1的数字,我们在中标记相应的条目b.如果我们看到的数字不符合这些范围,只需丢弃它并继续下一个.两种情况都是每个输入条目O(1),总O(n).

在我们完成输入处理之后,我们可以b在O(n)中找到布尔数组中的第一个非标记条目.

  • @Cristian但_answer_总是从1到100,001,这就是我们使用的事实.请再读一遍. (10认同)
  • N是[1..100,000]范围内的整数; 数组A的每个元素都是[-2,147,483,648..2,147,483,647]范围内的整数.只有当数组中的max元素为100,000时,您的解决方案才有效. (6认同)
  • 我实现了你的算法,它确实在 O(N) 中工作!: public int Solution(int[] A) { if (A.length == 0 || A.length == 1 && (A[0] > 1 | | A[0] <=0) ) { 返回 1; } boolean [] b = new boolean [A.length + 1]; for (int element: A) { if (element < 0 || element > b.length - 1) { 继续; b[元素] = true; } int i = 1; for (; i<b.length; i++) { if (b[i] == false) { return i; } 返回我;} (3认同)
  • @ sammy333:这个概念不会使解决方案无效:输入数字可以是任何签名的`int32`s,但我们只对`1`,`2`,...,`n + 1`的出现感兴趣他们,因为其中一个保证是答案. (2认同)
  • 加萨是对的。我们必须只为 100,001 个元素分配数组,而忽略其他元素。 (2认同)
  • 您如何检查数组A中数字的存在?使用`contains`会导致性能下降... (2认同)
  • @Legends 该解决方案不会直接检查数组“A”中是否存在任何数字。处理完“A”后,它检查“b[1]”是否为真,然后检查“b[2]”是否为真,依此类推,直到“b[N]”(或“b[N + 1]”,具体取决于关于实施)。每个这样的检查都是 O(1)。 (2认同)
  • 这个数组怎么样:[1, 299999] N = 2 的值。那么,我应该创建一个大小为 3 的布尔数组吗?如何从此布尔数组返回正确的结果“2”? (2认同)

Nik*_* B. 6

构建所有值的哈希表.对于数字1到n + 1,检查它们是否在哈希表中.其中至少有一个不是.打印出最低的这个数字.

这是O(n)的预期时间(你可以以很高的概率).请参阅@ Gassa的答案,了解如何避免哈希表支持大小为O(n)的查找表.

  • 无需哈希:因为我们知道答案是在前n + 1个正整数中,我们可以只考虑它们并丢弃其他所有内容.详情请见我的回答. (4认同)

Que*_*ger 6

今天写了这个,得到了100/100.不是最优雅的解决方案,但易于理解 -

public int solution(int[] A) {
    int max = A.length;
    int threshold = 1;
    boolean[] bitmap = new boolean[max + 1];

    //populate bitmap and also find highest positive int in input list.
    for (int i = 0; i < A.length; i++) {
        if (A[i] > 0 && A[i] <= max) {
            bitmap[A[i]] = true;
        }

        if (A[i] > threshold) {
            threshold = A[i];
        }
    }

    //find the first positive number in bitmap that is false.
    for (int i = 1; i < bitmap.length; i++) {
        if (!bitmap[i]) {
            return i;
        }
    }

    //this is to handle the case when input array is not missing any element.
    return (threshold+1);
}
Run Code Online (Sandbox Code Playgroud)


Ana*_*and 6

Java中的100%简单解决方案

public static int solution(final int[] A) 
{   
   Arrays.sort(A);
   int min = 1;

   // Starting from 1 (min), compare all elements, if it does not match 
   // that would the missing number.
   for (int i : A) {
     if (i == min) {
       min++;
     }
   }

   return min;
}
Run Code Online (Sandbox Code Playgroud)

  • 由于排序,这是O(n log n)而不是O(n)。 (4认同)
  • 这是一个聪明的做法。对于一个小的改进,我们可以在 `if (i == min)` 之后添加另一个分支 - 如果 `i &gt; min`,我们可以立即返回 `min`。 (2认同)

Mar*_*och 5

public int solutionMissingInteger(int[] A) {
    int solution = 1;
    HashSet<Integer> hashSet = new HashSet<>();

    for(int i=0; i<A.length; ++i){
        if(A[i]<1) continue;
        if(hashSet.add(A[i])){
            //this int was not handled before
            while(hashSet.contains(solution)){
                solution++;
            }
        }
    }

    return solution;
}
Run Code Online (Sandbox Code Playgroud)


小智 5

简单的 Java 解决方案。在正确性和性能方面得分为 100/100。

public int solution(int[] A) {
    int smallestMissingInteger = 1;
    if (A.length == 0) {
        return smallestMissingInteger;
    }
    Set<Integer> set = new HashSet<Integer>();
    for (int i = 0; i < A.length; i++) {
        if (A[i] > 0) {
            set.add(A[i]);
        }
    }
    while (set.contains(smallestMissingInteger)) {
        smallestMissingInteger++;
    }
    return smallestMissingInteger;

}
Run Code Online (Sandbox Code Playgroud)