关于算法:缺少整数变化-需要O(n)解决方案

Missing integer variation - O(n) solution needed

该问题来自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


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

现在,我们处理输入数组。如果找到从1到n 1的数字,则会在b中标记相应的条目。如果我们看到的数字不适合这些范围,则将其丢弃并继续下一个。两种情况的每个输入项均为O(1),总计O(n)。

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


使用Java的简单解决方案100%。

请注意,它是O(nlogn)解决方案,但100%产生了codility。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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);
}


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

这是O(n)个预期时间(您很有可能获得)。请参阅@Gassa的答案,以了解如何避免使用哈希表,而使用大小为O(n)的查找表。


简单的Java语言。在正确性和性能方面得分100/100。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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;

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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;
}

JavaScript 100%

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function solution(A) {
  let sortedOb = {};
  let biggest = 0;

  A.forEach(el => {
    if (el > 0) {
      sortedOb[el] = 0;
      biggest = el > biggest ? el : biggest;
    }
  });
  let arr = Object.keys(sortedOb).map(el => +el);
  if (arr.length == 0) return 1;

  for(let i = 1; i <= biggest; i++) {
    if (sortedOb[i] === undefined) return i;
  }
  return biggest + 1;
}

C#得分100%,

说明:使用查找表存储从输入数组中已经看到的值,我们只关心大于0且小于或等于输入数组上的长度的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    public static int solution(int[] A)
    {
        var lookUpArray = new bool[A.Length];

        for (int i = 0; i < A.Length; i++)
            if (A[i] > 0 && A[i] <= A.Length)
                lookUpArray[A[i] - 1] = true;

        for (int i = 0; i < lookUpArray.Length; i++)
            if (!lookUpArray[i])
                return i + 1;

        return A.Length + 1;
    }

100%Javascript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function solution(A) {
        // write your code in JavaScript (Node.js 4.0.0)
        var max = 0;
        var array = [];
        for (var i = 0; i < A.length; i++) {
            if (A[i] > 0) {
                if (A[i] > max) {
                    max = A[i];
                }
                array[A[i]] = 0;
            }
        }
        var min = max;
        if (max < 1) {
            return 1;
        }
        for (var j = 1; j < max; j++) {
            if (typeof array[j] === 'undefined') {
                return j
            }
        }
        if (min === max) {
            return max + 1;
        }
    }

我的解决方案。 100%。在Java中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Solution {
    public int solution(int[] A) {
        Arrays.sort(A);
        ArrayList<Integer> positive = new ArrayList<>();
        for (int i = 0; i < A.length; i++) {
            if(A[i] > 0)
                positive.add(A[i]);
        }
        if(positive.isEmpty()) return 1;
        if(positive.get(0) > 1) return 1;

        for(int i = 0; i < positive.size() - 1; i++) {
            if(positive.get(i + 1) - positive.get(i) > 1)
                return positive.get(i) + 1;
        }

        return positive.get(positive.size() - 1) + 1;
    }
    public static void main(String[] args) {
        Solution solution = new Solution();
        int[] A = {-5,1,2,3,4,6,7,8,9,5};
        System.out.println(solution.solution(A));
    }
}

这是我的解决方案,是Swift 4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public func solution(_ A: inout [Int]) -> Int {

    var minNum = 1
    var hashSet = Set<Int>()

    for int in A {
        if int > 0 {
            hashSet.insert(int)
        }
    }

    while hashSet.contains(minNum) {
        minNum += 1
    }

    return minNum

}

var array = [1,3,6]

solution(&array)

//答案:2


javascript 100%100%
首先对数组进行排序,您只需要扫描正元素即可找到索引1(如果数组中没有1,则答案为1)。然后在1之后搜索元素,直到找到缺失的数字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function solution(A) {
// write your code in JavaScript (Node.js 6.4.0)

   var missing = 1;
   // sort the array.
   A.sort(function(a, b) { return a-b });

   // try to find the 1 in sorted array if there is no 1 so answer is 1
   if ( A.indexOf(1) == -1) { return 1; }

   // just search positive numbers to find missing number
   for ( var i = A.indexOf(1); i < A.length; i++) {
      if ( A[i] != missing) {
        missing++;
        if ( A[i] != missing ) { return missing; }
      }
   }

   // if cant find any missing number return next integer number
   return missing + 1;
}

100%:Python排序例程不被视为作弊...

1
2
3
4
5
6
7
8
9
10
11
def solution(A):
   """
    Sort the array then loop till the value is higher than expected
   """
    missing = 1
    for elem in sorted(A):
        if elem == missing:
            missing += 1
        if elem > missing:
            break
    return missing

我相信解决方案比使用n(100,000)个元素的布尔数组"标记"相应的值更复杂。大小为n的布尔数组不会直接映射到可能的值范围(?2,147,483,648到2,147,483,647)。
我写的这个Java示例尝试通过基于距最大值的偏移量映射值来映射100K行。它还执行模量以将所得数组减小到与样本元素长度相同的大小。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/**
 *
 * This algorithm calculates the values from the min value and mods this offset with the size of the 100K sample size.
 * This routine performs 3 scans.
 * 1. Find the min/max
 * 2. Record the offsets for the positive integers
 * 3. Scan the offsets to find missing value.
 *
 * @author Paul Goddard
 *
 */
public class SmallestPositiveIntMissing {
    static int ARRAY_SIZE = 100000;
    public static int solve(int[] array) {
        int answer = -1;
        Maxmin maxmin = getMaxmin(array);
        int range = maxmin.max - maxmin.min;
        System.out.println("min:  " + maxmin.min);
        System.out.println("max:  " + maxmin.max);
        System.out.println("range:" + range);
        Integer[] values = new Integer[ARRAY_SIZE];
        if (range == ARRAY_SIZE) {
            System.out.println("No gaps");
            return maxmin.max + 1;
        }
        for (int val: array) {
            if (val > 0) {
                int offset = val - maxmin.min;
                int index = offset % ARRAY_SIZE;
                values[index] = val;
            }
        }
        for (int i = 0; i < ARRAY_SIZE; i++) {
            if (values[i] == null) {
                int missing = maxmin.min + i;
                System.out.println("Missing:" + missing);
                answer = missing;
                break;
            }
        }
        return answer;
    }

    public static Maxmin getMaxmin(int[] array) {
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        for (int val:array) {
            if (val >=0) {
                if (val > max) max = val;
                if (val < min) min = val;
            }
        }
        return new Maxmin(max,min);
    }

    public static void main(String[] args) {
        int[] A = arrayBuilder();
        System.out.println("Min not in array:" + solve(A));
    }

    public static int[] arrayBuilder() {

        int[] array = new int[ARRAY_SIZE];
        Random random = new Random();

        System.out.println("array:");
        for (int i=0;i < ARRAY_SIZE; i++) {
            array[i] = random.nextInt();
            System.out.print(array[i] +",");
        }
        System.out.println(" array done.");

        return array;
    }

}
class Maxmin {
    int max;
    int min;
    Maxmin(int max, int min) {
        this.max = max;
        this.min = min;
    }
}

对我有用。它不是O(n),但是简单得多:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.stream.*;
class Solution {
    public int solution(int[] A) {
        A = IntStream.of(A)
            .filter(x->x>0)
            .distinct()
            .sorted()
            .toArray();

        int min = 1;
        for(int val : A)
        {
            if(val==min)
                min++;
            else
                return min;
        }
        return min;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int[] copy = new int[A.length];
        for (int i : A)
        {
            if (i > 0 && i <= A.length)
            {
                copy[i - 1] = 1;
            }
        }
        for (int i = 0; i < copy.length; i++)
        {
            if (copy[i] == 0)
            {
                return i + 1;
            }
        }
        return A.length + 1;

迅捷3-100%

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public func solution(_ A : inout [Int]) -> Int {
// write your code in Swift 3.0 (Linux)

var solution = 1
var hashSet = Set<Int>()

    for int in A
    {
        if int > 0
        {
            hashSet.insert(int)

            while hashSet.contains(solution)
            {
                solution += 1
            }
        }
    }

    return solution
}

感谢玛丽安的上述回答。


这是我使用python的解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def solution(A):
    m = max(A)

    if m <= 0:
        return 1

    if m == 1:
        return 2

    # Build a sorted list with all elements in A
    s = sorted(list(set(A)))

    b = 0

    # Iterate over the unique list trying to find integers not existing in A
    for i in xrange(len(s)):
        x = s[i]

        # If the current element is lte 0, just skip it
        if x <= 0:
            continue;

        b = b + 1

        # If the current element is not equal to the current position,
        # it means that the current position is missing from A
        if x != b:
            return b

    return m + 1

得分100%/ 100%https://codility.com/demo/results/demoDCU7CA-SBR/


  • 创建一个长度为N 1的二进制数组bin(C使用基于0的索引)

  • 遍历二进制数组O(n)

  • 如果A [i]在bin的范围内,则将索引A [i]上的bin条目标记为存在或正确。
  • 再次遍历二进制数组
  • 任何不存在或为false的bin条目的索引是您丢失的整数
  • ?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    #include<stdio.h>
    #include<stdlib.h>
    #include<stdbool.h>

    int solution(int A[], int N) {
        // write your code in C99 (gcc 6.2.0)
        int i;
        bool *bin = (bool *)calloc((N+1),sizeof(bool));

        for (i = 0; i < N; i++)
        {
            if (A[i] > 0 && A[i] < N+1)
            {
                bin[A[i]] = true;
            }
        }

        for (i = 1; i < N+1; i++)
        {
            if (bin[i] == false)
            {
                break;
            }
        }

        return i;
    }

    甜美的Swift版本。 100%正确

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    public func solution(inout A : [Int]) -> Int {
        //Create a Hash table
        var H = [Int:Bool]()
        // Create the minimum possible return value
        var high = 1
        //Iterate
        for i in 0..<A.count {
            // Get the highest element
            high = A[i] > high ? A[i] : high
            // Fill hash table
            if (A[i] > 0){
                H[A[i]] = true
            }
        }
        // iterate through possible values on the hash table
        for j in 1...high {
            // If you could not find it on the hash, return it
            if H[j] != true {
                return j
            } else {
                // If you went through all values on the hash
                // and can't find it, return the next higher value
                // e.g.: [1,2,3,4] returns 5
                if (j == high) {
                    return high + 1
                }
            }
        }
        return high
    }

    PHP中的100%https://codility.com/demo/results/trainingKFXWKW-56V/

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    function solution($A){
        $A = array_unique($A);
        sort($A);
        if (empty($A)) return 1;
        if (max($A) <= 0) return 1;
        if (max($A) == 1) return 2;
        if (in_array(1, $A)) {
        $A = array_slice($A, array_search(1, $A)); // from 0 to the end
        array_unshift($A, 0); // Explanation 6a
        if ( max($A) == array_search(max($A), $A)) return max($A) + 1; // Explanation 6b
            for ($i = 1; $i <= count($A); $i++){
                    if ($A[$i] != $i) return $i; // Explanation 6c
            }
        } else {
            return 1;
        }
    }

    //说明

  • 删除所有重复项
  • 从最小到最大排序
  • 如果数组为空,则返回1
  • 如果数组的最大值为零或更小,则返回1
  • 如果数组的最大值为1,则返回2 //下一个正整数
  • 所有其他情况:
    6a)将数组从值1拆分到末尾,并在第一个数字前加0
    6b)如果array的最后一个元素的值是array的最大值,则该数组升序,因此我们返回max 1 //下一个正整数
    6c)如果数组未升序,我们会通过以下函数找到一个缺失的数字:如果element的键不是该元素的值,但它应该是(A = [0 => 0,1 => 1,2 => 3,...]),我们返回键,因为我们期望键和值相等。

  • 我的100/100解决方案

    1
    2
    3
    4
    5
    6
    7
    8
    9
      public int solution(int[] A) {
            Arrays.sort(A);
            for (int i = 1; i < 1_000_000; i++) {
                if (Arrays.binarySearch(A, i) < 0){
                    return i;
                }
            }
            return -1;
        }

    此解决方案在测试中获得100/100:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    class Solution {
        public int solution(int[] A) {

            int x = 0;
            while (x < A.length) {
                // Keep swapping the values into the matching array positions.
                if (A[x] > 0 && A[x] <= A.length && A[A[x]-1] != A[x])  {
                    swap(A, x, A[x] - 1);
                } else {
                    x++; // Just need to increment when current element and position match.
                }
            }

            for (int y=0; y < A.length; y++) {
                // Find first element that doesn't match position.
                // Array is 0 based while numbers are 1 based.
                if (A[y] != y + 1)  {
                    return y + 1;
                }
            }

            return A.length + 1;
        }

        private void swap (int[] a, int i, int j) {
            int t = a[i];
            a[i] = a[j];
            a[j] = t;
        }
    }

    C的代码,实际上,它可以用于任何编程语言,而无需更改逻辑。

    逻辑是N的总和是N*(N+1)/2

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    int solution(int A[], int N) {

        // write your code in C99
        long long sum=0;
        long long i;
        long long Nsum=0;

        for(i=0;i<N;i++){
            sum=sum + (long long)A[i];
        }

        if (N%2==0){
            Nsum= (N+1)*((N+2)/2);
            return (int)(Nsum-sum);
        }
        else{
            Nsum= ((N+1)/2)*(N+2);
            return (int)(Nsum-sum);
        }    

    }

    这给出了100/100的得分。


    这是我的解决方案,它的评估产率为88%-时间为O(n),正确性为100%,性能为75%。记住-可以包含所有负数或超过100,000的数字的数组。上面的大多数解决方案(带有实际代码)得分要低得多,或者根本不起作用。其他问题似乎与Codility上出现的Missing Integer问题无关。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    int compare( const void * arg1, const void * arg2 )
    {
        return *((int*)arg1) - *((int*)arg2);
    }

    solution( int A[], int N )
    {
        // Make a copy of the original array
        // So as not to disrupt it's contents.
        int * A2 = (int*)malloc( sizeof(int) * N );
        memcpy( A2, A1, sizeof(int) * N );

        // Quick sort it.
        qsort( &A2[0], N, sizeof(int), compare );

        // Start out with a minimum of 1 (lowest positive number)
        int min = 1;
        int i = 0;

        // Skip past any negative or 0 numbers.
        while( (A2[i] < 0) && (i < N )
        {
            i++;
        }

        // A variable to tell if we found the current minimum
        int found;
        while( i < N )
        {
            // We have not yet found the current minimum
            found = 0;
            while( (A2[i] == min) && (i < N) )
            {
                // We have found the current minimum
                found = 1;
                // move past all in the array that are that minimum
                i++;
            }
            // If we are at the end of the array
            if( i == N )
            {
                // Increment min once more and get out.
                min++;
                break;
            }
            // If we found the current minimum in the array
            if( found == 1 )
            {
                // progress to the next minimum
                min++;
            }
            else
            {
                // We did not find the current minimum - it is missing
                // Get out - the current minimum is the missing one
                break;
            }
        }

        // Always free memory.
        free( A2 );
        return min;
    }

    可能会有所帮助,我正在使用算术级数计算总和,并使用二进制searach提取元素。用几百个值的数组检查效果很好。因为在2步中有一个for循环和迭代,所以O(n / 2)或更小

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    def Missingelement (A):
        B = [x for x in range(1,max(A)+1,1)]
        n1 = len(B) - 1
        begin = 0
        end = (n1)//2
        result = 0
        print(A)
        print(B)
        if (len(A) < len(B)):
            for i in range(2,n1,2):
                if BinSum(A,begin,end) > BinSum(B,begin,end) :
                   end = (end + begin)//2
                   if (end - begin) <= 1 :
                    result=B[begin + 1 ]    
                elif BinSum(A,begin,end) == BinSum(B,begin,end):
                    r = end - begin
                    begin = end
                    end = (end + r)

                if begin == end :
                    result=B[begin + 1 ]    
        return result        


    def BinSum(C,begin,end):
        n = (end - begin)

        if end >= len(C):
            end = len(C) - 1
        sum =  n*((C[begin]+C[end])/2)
        return sum                


    def main():
        A=[1,2,3,5,6,7,9,10,11,12,14,15]
        print ("smallest number missing is",Missingelement(A))
    if __name__ == '__main__': main()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
        static int spn(int[] array)
        {
            int returnValue = 1;
            int currentCandidate = 2147483647;

            foreach (int item in array)
            {
                if (item > 0)
                {
                    if (item < currentCandidate)
                    {
                        currentCandidate = item;
                    }
                    if (item <= returnValue)
                    {
                        returnValue++;
                    }
                }
            }

            return returnValue;
        }