【问题标题】:What is the right way to solve Codility's PermMissingElem test? (Java)解决 Codility 的 PermMissingElem 测试的正确方法是什么? (爪哇)
【发布时间】:2015-04-25 05:16:27
【问题描述】:

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

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

你的目标是找到那个缺失的元素。

写一个函数:

类解决方案 { 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查找数组中的最低值和最高值,并从最低到最高遍历所有可能的值,然后返回缺失的值。

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

“空列表和单个元素”

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

“单个元素”

“两个元素”

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

【问题讨论】:

  • 您缺少的是,这不是编程问题,而是数学问题。它在一组编程问题中确实没有任何合理的位置。

标签: java algorithm


【解决方案1】:

这个问题有一个数学解,基于sum of consecutive integers from 1 to n is equal to n(n+1)/2.

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

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

空间复杂度为O(1)

【讨论】:

  • 谢谢。这个答案通过了所有测试用例和条件,坦率地说,我自己永远也想不出这个。
  • 谢谢,如此基本但非常简洁的解决方案。我自己也想不通
  • 有人用 Python 实现过吗?
  • 它不适用于 A = [12, 13, 1]。我错过了什么吗?
【解决方案2】:

这个问题是时间复杂性课程的一部分。

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)

【讨论】:

  • 它不适用于输入 A = [12, 13, 1],我错过了什么吗?
  • @GaurangPopat 它不能与您的数组一起使用,因为我们正在解决这个问题:转到本文档的第“4”页:[链接](codility.com/media/train/1-TimeComplexity.pdf)数组必须包含所有元素.我解释一下:[1,2,3,5,6,7,8,4] 这个数组包含 8 个元素,并且包含从 1 到 8 的所有数字。你的数组 [12,13,1] 包含 3 个元素,所以它必须是:[1,2,3] OR, [1,2,3,4,5,6,7,8,9,10,11,12,13] 是一个完整的数组。
  • @GaurangPopat 请记住,这里的目标是找到 Array 的缺失元素(参见标题:PermMissingElement)-> 缺失元素。我希望现在一切都清楚了:)
  • 确实! {12,13,1} 不是有效输入。谢谢!
  • 问题应该写的很简单,但问题本身很难理解。
【解决方案3】:

问题陈述清楚地指出该数组将由“N 个不同的整数”组成,因此 N 必须至少为 2。如果我们用英文写 N=0 和 N=1,它们就根本没有意义,例如“一个由 0 个不同整数组成的数组……”。

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

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

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

【讨论】:

  • 当我看到它时,我告诉自己完全一样的事情......
  • 如果数组有零个元素,那么显然数字 1 丢失了。
  • 完全正确!!!可笑的失败
【解决方案4】:

另一种 100% 解决方案:

实际上甚至不需要使用 64 位整数来避免几个测试试图触发的溢出(在撰写本文时数组大小为 100000 的那些)。你可以只用一个 sum 变量就可以逃脱。最后一行通过以不同方式实现 n(n+1)/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); } }

【讨论】:

  • 如果担心溢出,也可以用异或代替求和。
【解决方案5】:

我在 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】:

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

    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;
    }
    

    【讨论】:

      【解决方案7】:

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

      function solution($A) {
      
          $size = count($A) + 1;
          $total = ($size * ($size + 1)) / 2;
      
          return  $total - array_sum($A);
      
      }
      

      【讨论】:

        【解决方案8】:
        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); 
            }
        

        【讨论】:

        • 举个例子:int[] a = {1,2,4,5};这里缺少 3 号。所以实际的数组应该是 {1,2,3,4,5};缺失数 = 预期数组的总和 - 实际数组的总和; = SUM {1,2,3,4,5} - SUM{1,2,4,5} SUM {1,2,3,4,5} = N (N +1) / 2; (5 * 6) = 15 SUM{1,2,4,5} = 12 缺失数 = 15 - 12 = 3
        【解决方案9】:

        这是另一个使用 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;
        }
        

        【讨论】:

          【解决方案10】:

          Golang 解决方案:

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

          【讨论】:

            【解决方案11】:

            虽然我重视数学解决方案,但它并不容易理解。
            所以这里有一个简单的解决方案,在代码性方面得分为 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;
            }
            

            【讨论】:

            • 只得到了 10% 的这个......这是完全错误的,并且没有考虑到缺少第一个和最后一个 N+1 元素的几个边缘情况
            • 其实这个解决方案的得分是100%。它很简单而且不是数学的。
            • 这远非理想。毕竟,他们正在请求 time_efficiency... 排序通常是 O{nlogn} 或 O{n^2} 事件(我不是 Java 人,我不知道 Arrays.sort(A) voodoo 的幕后黑手是什么)... 数学方法在 O{n} 内完成工作。
            【解决方案12】:

            OBJECTIVE-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;
                }
            }
            

            【讨论】:

              【解决方案13】:

              OBJECTIVE-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;
                  }
              }
              

              【讨论】:

                【解决方案14】:

                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
                }
                

                【讨论】:

                  【解决方案15】:
                  // 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();
                          }
                  

                  【讨论】:

                  • 您能否解释一下这段代码为什么以及如何提供问题的答案?几句话可能就足够了。谢谢。
                  • public static int GetPermMissingElem(int[] A) { if (A.length == 0) return 1; int sumOfAllNumbers = 0; for (int num : A) sumOfAllNumbers += num;长 N = A.长度; long expectedSumOfAllNumbers = ((N + 1) * (N + 2)) / 2; long missingNumber = expectedSumOfAllNumbers - sumOfAllNumbers;返回(int)缺失的数字; }
                  【解决方案16】:

                  这得到了 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。

                  【讨论】:

                    【解决方案17】:

                    虽然现在连续整数的总和有助于获得一个快速的解决方案,但使用额外的数组和 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】:

                      我使用这个 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;
                          }
                      
                      }
                      

                      【讨论】:

                        【解决方案19】:

                        鲁比,100% 通过:

                        def solution(a)
                          n = a.length + 1
                          sum = n * (n + 1)/2
                          return sum - a.inject(0,:+)
                        end
                        

                        【讨论】:

                          【解决方案20】:

                          我对此有疑问,但这只是因为我不了解所有情况。 这是我在 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;
                              }
                          }
                          

                          分析总结 解获得满分。

                          亲切的问候内纳德

                          【讨论】:

                            【解决方案21】:
                                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;
                                }
                            }
                            

                            【讨论】:

                              【解决方案22】:

                              Swift 解决方案 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
                              }
                              

                              【讨论】:

                                【解决方案23】:

                                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);
                                    }
                                }
                                

                                【讨论】:

                                  【解决方案24】:

                                  这是我的解决方案。

                                  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);
                                  

                                  【讨论】:

                                    【解决方案25】:

                                    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%

                                    【讨论】:

                                      【解决方案26】:

                                      用 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

                                      附言使用Long 原始类型执行操作,因为您可能会遇到一些Int 限制。

                                      【讨论】:

                                        【解决方案27】:

                                        我认为最好的方法是通过 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

                                        【讨论】:

                                          【解决方案28】:

                                          这是一项编程测试,而不是数学测试。 100% 使用 Javascript:

                                          function solution(A) {
                                              let m = {};
                                              for(let i of A) {
                                                  m[i] = 1;
                                              }
                                          
                                              for(let i = 1; i <= (A.length + 1); ++i) {
                                                  if(m[i] === undefined)
                                                      return i;
                                              }
                                          
                                              return 1;
                                          }
                                          

                                          【讨论】:

                                            【解决方案29】:

                                            我的解决方案尝试将求和时间减半。检测到的时间复杂度: O(N) 或 O(N * log(N))

                                            `

                                                int sumArray = 0;
                                                int t = A.length-1;
                                                for (int i=0; i<= t-i; i++) {
                                                    if(i == t-i){
                                                        sumArray += A[i];
                                                        break;
                                                    }
                                                    sumArray += (A[i] + A[t-i]);
                                                }
                                                int n = (A.length + 1);
                                                int total = BigDecimal.valueOf(n).pow(2).add(BigDecimal.valueOf(n)).divide(BigDecimal.valueOf(2)).intValue();
                                                return total - sumArray;
                                            `
                                            

                                            【讨论】:

                                              【解决方案30】:
                                              Java solution got 100%:
                                              
                                              
                                              public int solution(int[] A) {
                                                  
                                                  Arrays.sort(A);
                                                  
                                                  if (A.length == 0) {
                                                      return 1;
                                                  }
                                              
                                                  if (A[0] != 1) {
                                                      return 1;
                                                  }
                                              
                                                  for (int i = 0; i < A.length; i++) {
                                                      if (A[i] != i + 1) {
                                                          return A[i] - 1;
                                                      }
                                                  }
                                              
                                                  return A[A.length - 1] + 1;
                                              }
                                              

                                              【讨论】:

                                                猜你喜欢
                                                • 1970-01-01
                                                • 2015-01-05
                                                • 2012-10-10
                                                • 2010-10-10
                                                • 1970-01-01
                                                • 1970-01-01
                                                • 1970-01-01
                                                • 1970-01-01
                                                • 1970-01-01
                                                相关资源
                                                最近更新 更多