解决Codility的PermMissingElem测试的正确方法是什么? (Java)的

时间:2015-04-25 05:16:28

标签: java algorithm

我从Codility的代码测试练习中得到以下问题:

给出了由N个不同整数组成的零索引数组A.该数组包含[1 ..(N + 1)]范围内的整数,这意味着只缺少一个元素。

您的目标是找到缺少的元素。

写一个函数:

  

class Solution {public int solution(int [] A); }

给定零索引数组A,返回缺少元素的值。

例如,给定数组A使得:

  

A [0] = 2    A [1] = 3    A [2] = 1    A [3] = 5

该函数应该返回4,因为它是缺少的元素。

假设:

  

N是[0..100,000]范围内的整数;   A的元素都是截然不同的;   数组A的每个元素是[1 ..(N + 1)]范围内的整数。

复杂度:

  

预期的最坏情况时间复杂度为O(N);   预期的最坏情况空间复杂度为O(1),超出输入存储(不包括计算输入参数所需的存储空间)。

可以修改输入数组的元素。

我的方法是将给定数组转换为ArrayList,使用ArrayList查找数组中的最低和最高值,并从最低到最高迭代所有可能的值,然后返回缺失值。

这解决了示例问题,但我的问题似乎是在给定数组的以下条件下我无法得到正确的答案:

  

“空列表和单个元素”

     

“缺少第一个或最后一个元素”

     

“单一元素”

     

“两个要素”

我做错了什么,解决这个问题的正确方法是什么?

29 个答案:

答案 0 :(得分:16)

这个问题有一个数学解决方案,基于sum of consecutive integers from 1 to n is equal to n(n+1)/2的事实。

使用此公式,我们可以计算1 to N+1的总和。然后,O(N)时间复杂度,我们计算数组中所有元素的实际总和。

完整和实际总数之间的差异将产生缺失元素的值。

空间复杂度为O(1)

答案 1 :(得分:2)

问题陈述明确指出数组将由“N个不同的整数”组成,因此N必须至少为2. N = 0且N = 1如果我们用英语写它们就没有意义,例如“由0个不同整数组成的数组......”。

  

给出了由N个不同整数组成的零索引数组A.该数组包含[1 ..(N + 1)]范围内的整数,这意味着只缺少一个元素。

根据这些初始条件和陈述的假设,“单一元素”,“空列表”等测试是完全不合适的。

正确的生产代码很可能必须测试无效条件,但这不是挑战的既定目标。

答案 2 :(得分:2)

另一个100%的解决方案:

实际上甚至不需要使用64位整数来避免一些测试试图触发的溢出(在编写时阵列大小为100000的那些)。而你只能使用一个和变量。最后一行通过不同地实现n(n + 1)/ 2来避免溢出,因此除以2的除法发生在“早期”:

C#: class Solution { public int solution(int[] A) { var sum = 0; for(int i = 0; i < A.Length; i++) sum += A[i];
return A.Length % 2 == 0 ? -sum + (A.Length/2 + 1) * (A.Length+1) : -sum + (A.Length/2 + 1) * (A.Length+2); } }

答案 3 :(得分:1)

Golang解决方案:

func Solution(A []int) int {
  n := len(A) + 1
  total := n * (n + 1) /2
  for _, e := range A {
    total -= e
  }
  return total
}

答案 4 :(得分:1)

这是使用JavaScript的另一种解决方案,经过100%测试

function solution(A) {
    let maximumNumber = A.length + 1;
    let totalSum = (maximumNumber*(maximumNumber + 1))/2;
    let partialSum = 0;
    for(let i=0; i<A.length; i++) {
        partialSum += A[i];
    }
    return totalSum - partialSum;
}

答案 5 :(得分:1)

我在Java中的解决方案100% 检测到的时间复杂度: O(N)

import java.util.*;

class Solution {
public int solution(int[] arr) {

    if(arr.length == 0) return 1;

    int sumArr = 0;


    for(int i=0; i < arr.length; i++){

        sumArr = sumArr + arr[i];

    }


    int sumN = 0;

     for(int i=1; i <= arr.length+1; i++){

        sumN = sumN + i;

    }


    if(sumArr == sumN)  return arr.length;


    return  sumN - sumArr;
}

}

答案 6 :(得分:0)

我认为最好的方法是通过 XOR,它干净、优雅且快速。不需要数学知识,只需要CS!与其他总结方式相比,这还有另一个优势,因为我们只是在进行按位运算,因此不会出现整数溢出。

时间上的 O(n),空间上的 O(1)。

代码如下(Javascript),只需要一个循环:

function solution(A) {
    // write your code in JavaScript (Node.js 8.9.4)

    let missingNumber = A.length + 1;
    // Sum up 1+2+3+...+N+(N+1) AND all of A[i] (except value not present in A[i] obviously). The value not present in A[i] is the odd one out. Note `missingNumber` starts with `A.length + 1` (i.e. N+1) because we loop N times here only...
    for(let i = 0; i < A.length; ++i) {
       missingNumber ^= (i + 1) ^ A[i];
    }
    
    return missingNumber;
}

https://florian.github.io/xor-trick/ 对理解 XOR 有很好的指导作用。

基本上采用 X ^ X equals 0 的想法,我们使用它来利用重复值抵消值,以便我们得到非重复值(即剩下的缺失元素)。

这是有效的,因为问题约束保证 the elements of A are all distinct。所以我们可以将它们组合在一起来利用这个技巧。如果这是一个可以复制元素的排列,这不起作用,即 PermCheck

答案 7 :(得分:0)

附上用 kotlin 编写的解决方案:

fun solution(A: IntArray): Int {
        val lastElement = A.size + 1
        // including missing element
        val arraySize = A.size + 1L
        var result = (arraySize * (1 + lastElement)) / 2
        A.forEach {
            result -= it
        }
        return result.toInt()
    }

附言使用了 Arithmetic progression sum formula

P.P.S.使用 Long 原始类型执行操作,因为您可能面临一些 Int 限制。

答案 8 :(得分:0)

java 解决方案:

public int solution(int[] A) {
    int nExpected = A.length + 1;
    long seriesSumExpected = nExpected * (nExpected + 1L) / 2;
    long seriesSum = getSum(A);
    return (int) (seriesSumExpected - seriesSum);
}

private long getSum(int[] A) {
    long sum = 0L;
    for (int i : A) {
        sum += i;
    }
    return sum;
}

任务得分:100%
正确性:100%
性能:100%

答案 9 :(得分:0)

这是我的解决方法。

const assert = require("assert").strict;

function solution(A) {
    const n = A.length + 1;
    const sum = (n * (n + 1)) / 2;
    const sum2 = A.reduce((a, b) => a + b, 0);
    return sum - sum2;
}


assert.strictEqual(solution([2, 3, 1, 5]), 4);
assert.strictEqual(solution([]), 1);
assert.strictEqual(solution([1]), 2);

答案 10 :(得分:0)

Java解决方案:

// Import Dependencies
import java.util.*;


class Solution {
    public int solution(int[] A) {
        // write your code in Java SE 8
        long N = A.length+1;
        long realSum = N*(N+1)/2;
        
        long foundSum = 0;
        for(int i=0;i<N-1;i++){
            foundSum = foundSum + A[i];
        }
        long answer = (realSum - foundSum);
        
        return (int)(answer);
    }
}

答案 11 :(得分:0)

快速解决方案100%通过

import Foundation
import Glibc

public func solution(_ A : inout [Int]) -> Int {

  let sortedArray = A.sorted(by: { $0 < $1 })

  for i in 0..<sortedArray.count {
      if sortedArray[i] != i+1 {
          return i+1
      }    
  }

  return A.count + 1
}

答案 12 :(得分:0)

    using System;
// you can also use other imports, for example:
// using System.Collections.Generic;

// you can write to stdout for debugging purposes, e.g.
// Console.WriteLine("this is a debug message");

class Solution {
    public int solution(int[] A) {
        // write your code in C# 6.0 with .NET 4.5 (Mono)
        int i, j = 0, n = A.Length;
            if (A != null && n != 0)
            {
                Array.Sort(A);
                for (j = A[0], i = 0; i < n; i++, j++)
                {
                    if (j == A[i]) continue;
                    else return j;
                }

                if (i == n) return (A[0] == 2) ? 1 : ++A[--n];

            }
            else return 1;
            return -1;
    }
}

答案 13 :(得分:0)

我对此感到麻烦,但这仅仅是因为我不了解所有情况。 这是我在Java中的解决方案。稍长一点(我不能缩小),但是分数是100%。

class Solution {
    public int solution(int[] A) {
        Arrays.sort(A);
        if (A.length == 1) {
            if (A[0] == 1) {
                return A.length + 1;
            } else {
                return A[0] - 1;
            }
        }
        for (int n = 0; n < A.length - 1; n++) {
            if (A.length == 2) {
                if (A[n] == 1) {
                    if (A[n] + 1 != A[n + 1]) {
                        return A[n] + 1;
                    }
                    return A.length + 1;
                } else {
                    return 1;
                }
            } else {
                if (A[0] != 1) {
                    return 1;
                }
                if (A[n] + 1 != A[n + 1]) {
                    return A[n] + 1;
                }
            }
        }
        return A.length + 1;
    }
}

分析摘要 该解决方案获得了满分。

向内纳德致敬

答案 14 :(得分:0)

Ruby,100%通过:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

答案 15 :(得分:0)

我使用此Java代码作为解决方案。得到了100%

class Solution {
    public int solution(int[] A) {
        int result = 0;
        Set<Integer> set = new HashSet<>();
        for (int x : A) {
            set.add(x);
        }
        for (int x = 1; x < set.size() + 2; x++) {
            if (!set.contains(x)) {
                return x;
            }
        }
        return result;
    }

}

答案 16 :(得分:0)

您可以使用Array首先对元素进行排序,然后使用simple for循环对其进行迭代,并找到缺少的值。 这是我的简单代码,其中检测到的时间复杂度为O(N)O(N * log(N))(在Codility中)。

public static int solution(int[] A) {

    int size = A.length;
    int count = 1;

    Arrays.sort(A);

    for (int i = 0; i < size; i++) {
        if (A[i] != count)
            return count;
        count++;
    }
    return count;
}

答案 17 :(得分:0)

尽管现在连续整数的总和将有助于获得快速的解决方案,但使用额外的数组和2O(N)复杂度而不计算总和可能是一种快速但不具有内存效率的解决方案。

这是我的解决方法:

class Solution {

    public int findFalse(boolean [] ar){

        for (int j = 0; j<ar.length; ++j){
            if(ar[j]==false){
                return j;
            }
        }
        return -1;
    }

    public int solution(int[] A) {
        // write your code in Java SE 8

        boolean [] M = new boolean[A.length+1];

        for (int i:A){
            M[i-1] = true;   
        }

        int missingValue = findFalse(M) +1 ;
        return missingValue;

    }
}

答案 18 :(得分:0)

这获得了100%的Codality。它使用非常基本的数学。对于数组: {2,3,1,5}  1,2,3,4,?

  1. 所有索引的总和+ 1,再加上缺少的索引+ 1,以得到总计。
  2. 然后您可以减去数组的总和:(1 + 2 + 3 + 4 + 5 = 15)-(2 + 3 + 1 + 5 = 11)= 4
    public int solution(int A[]) {

        if (A == null) return 0;
        if(A.length == 0) return 1;

        int total = 0;
        int max = A.length + 1;
        for (int i = 0; i < A.length; i++) {
            total += A[i];
            max += i + 1;
        }

        return (max - total) < 0 ? 0 : (max - total);
    }

这是我不得不抬头的一件事,尽管这让我很烦,但我不明白。 if(A.length == 0) return 1; 这使IMO毫无意义。如果数组长度为零,则IMO应为零。

答案 19 :(得分:0)

// Solution with LinQ.
// Task Score: 100%
// Correctness: 100%
// Performance: 100%

using System.Linq;
public static int GetPermMissingElem(int[] A)
        {
            if (A.Length <= 0)
                return 1;

            int size = A.Length;
            System.Collections.Generic.List<int> missing = Enumerable.Range(1, A[size - 1]).Except(A.ToList()).ToList();
            if (!missing.Any())
                return A[size -1] + 1;

            return missing.First();
        }

答案 20 :(得分:0)

Swift 4中的100%解决方案:

public func solution(_ A : inout [Int]) -> Int {
    // first we simply calculate the sum on the given array
    var sum = 0
    for element in A {
        sum += element
    }

    // as the sum of consecutive ints is given by n(n+1)/2,
    // we calculate the expected sum from 1 to n + 1
    // (which is ((n+1)(n+2))/2) and substract the actual sum
    // to get the missing element
    return ((A.count + 1) * (A.count + 2) / 2) - sum
}

答案 21 :(得分:0)

这是PHP中使用从1到n的连续整数之和等于n(n + 1)/ 2的解决方案。

function solution($A) {

    $size = count($A) + 1;
    $total = ($size * ($size + 1)) / 2;

    return  $total - array_sum($A);

}

答案 22 :(得分:0)

此问题是“时间复杂性”课程的一部分。

https://codility.com/media/train/1-TimeComplexity.pdf

实际上,最后有解释如何在不进行任何循环的情况下计算数组中元素的总和。

这是Python3中的最终解决方案:

def solution(A):

    n = len(A)+1
    result = n * (n + 1)//2

    return result - sum(A)

答案 23 :(得分:0)

目标C解决方案O(N)-XOR方法

Codility提供的结果

任务得分:100%
正确性:100%
效果:100%

时间复杂度

最差的时间复杂度是O(N)或O(N * log(N))

Xcode Solution Here

+(int)XORSolution:(NSMutableArray*)array {

    /******** Algorithm Explanation  ********/

    // FACTS
    //      Use of XOR operator
    //      Edge case: when the array is empty [], we should return 1
    //      XOR of a number with itself is 0.
    //      XOR of a number with 0 is number itself.


    // STEP 1
    //       XOR all the array elements, let the result of XOR be X1.
    // STEP 2
    //       XOR all numbers from 1 to n, let XOR be X2.
    // STEP 3
    //       XOR of X1 and X2 gives the missing number.

    int n = (int)[array count];

    // Edge Case
    if(n==0){
        return 1;
    }
    else {

        // STEP 1
        /* XOR of all the elements in array */
        int x1 = 0;
        for (int i=0; i<n; i++){
            x1 = x1 ^ [[array objectAtIndex:i]intValue];
        }

        // STEP 2
        /* XOR of all the elements from 1 to n+1 */
        int x2 = 0;
        for (int i=1; i<=(n+1); i++){
            x2 = x2 ^ i;
        }

        // STEP 3
        int missingElement = x1 ^ x2;
        return missingElement;
    }
}

答案 24 :(得分:0)

目标C解决方案O(N)-SET方法

Codility提供的结果

任务得分:100%
正确性:100%
效果:100%

时间复杂度

最差的时间复杂度是O(N)或O(N * log(N))

Xcode Solution Here

+(int)SETSolution:(NSMutableArray*)array {

    /******** Algorithm Explanation  ********/

    // FACTS
    //      Use of a NSSet to verify if the missing element exist or not.
    //      Edge case: when the array is empty [], we should return 1

    // STEP 1
    //     validate the edge case

    // STEP 2
    //      Generate a NSSet with the array elements in order to search an element faster

    // STEP 3
    //      Use a for loop and find the current 'i' in the NSSset
    //      If an elements doesn't exist in the NSSet, that means it's the missing element.

    int n = (int)[array count];
    int missing = 0;
    // STEP 1
    if (n == 0) {
        missing = 1;
        return missing;
    }
    else {
        // STEP 2
        NSSet *elements = [NSSet setWithArray:array];

        // STEP 3
        for (int i = 1; i <= (n+1); i++) {
            // O(N) or O(N * log(N)) depending of  required iterations
            if (![elements containsObject:[NSNumber numberWithInt:i]]) {
                missing = i;
                return missing;
            }
        }
        return  missing;
    }
}

答案 25 :(得分:0)

虽然我看重数学解决方案,但它并不那么容易理解。
因此,这是一个简单的解决方案,其Codility得分为100%。

import java.util.*;

public int solution(int[] A) {
    int missing = 1; // missing number 1 already
    Arrays.sort(A);

    // check numbers one by one
    for (int i = 0; i < A.length; i++) {
        if (A[i] == missing) {    // we found the missing number !
            missing = A[i]+1;    // add +1 and keep checking
        }
    }
    return missing;
}

答案 26 :(得分:0)

private static int getMissingElementInArrayNew(int[] A) throws IOException {
        double n =  A.length + 1;
        double totalSum = (double) ((n * (n + 1)) / 2);

        for (int i = 0; i < A.length; i++) {
            totalSum -= A[i];
        }

        return (int) (totalSum == 0 ? A.length + 1 : totalSum); 
    }

答案 27 :(得分:-1)

这是我的代码,也是100%的结果:

class Solution {
    public int solution(int[] A) {
        // write your code in Java SE 8
        int value = A.length;
        Arrays.sort(A);
        if (value == 0) return 1;
        if (value == 1) { 
           if ( A[0] == 1 ) {
             return A[0] + 1;  
           } 
           else {
             return A[0] - 1;   
           } 
        }

        for (int x = 1; x <= value; ++x) {
           if ( A[x - 1] != x ) {
              return x;     
           }
        }

       return A[value - 1] + 1;
    }
}

答案 28 :(得分:-1)

我在C#中尝试了这个解决方案,并在100%中得分100%

https://codility.com/programmers/lessons/3-time_complexity/perm_missing_elem/

class Solution
{
    public int solution(int[] A)
    {
        long sum = 0, sum1 = 0;
        int i;

        for (i = 0; i < A.Length; i++)
        {
            sum += Convert.ToInt64(i + 1);
            sum1 += Convert.ToInt64(A[i]);
        }
        sum += Convert.ToInt64(i+1);

        return Convert.ToInt32(sum - sum1);
    }
}