如何以较少的时间复杂度编写代码以找到给定数组范围内的缺失元素?

时间:2018-06-20 07:11:51

标签: javascript performance time-complexity big-o

我的函数应该在给定的数组范围内返回缺少的元素。 因此,我首先对数组进行排序,并检查i和i + 1之间的差是否不等于1,我将返回缺少的元素。

// Given an array A such that:
// A[0] = 2
// A[1] = 3
// A[2] = 1
// A[3] = 5
// the function should return 4, as it is the missing element.

function solution(A) {
  A.sort((a,b) => {
    return b<a;
  })
  var len = A.length;
  var missing;
  for( var i = 0; i< len; i++){
    if( A[i+1] - A[i] >1){
      missing = A[i]+1;
    }
  }
  return missing;
}

我确实喜欢上面的内容,但是如何更有效地编写它呢?

7 个答案:

答案 0 :(得分:19)

您可以通过使用缺失值集来使用单循环方法。

在循环中,从缺失的集合中删除每个数字。

如果找到一个新的最小值,则所有缺失的数字都将添加到缺失数字集中,除了最小值和新的最大数字。

缺少的数字集最后包含结果。

function getMissing(array) {
    var min = array[0],
        max = array[0],
        missing = new Set;
    
    array.forEach(v => {
        if (missing.delete(v)) return;                   // if value found for delete return
        if (v < min) while (v < --min) missing.add(min); // add missing min values
        if (v > max) while (v > ++max) missing.add(max); // add missing max values
    });
    return missing.values().next().value;                // take the first missing value
}

console.log(getMissing([2, 3, 1, 5]));
console.log(getMissing([2, 3, 1, 5, 4, 6, 7, 9, 10]));
console.log(getMissing([3, 4, 5, 6, 8]));

答案 1 :(得分:5)

您可以将每个值放入sort中,而不是Set,找到最小值,然后从最小值开始进行迭代,检查集合中是否有相关数字{{1 }}。 (集合保证了O(N)的查找时间)

O(1)

答案 2 :(得分:2)

好吧,从问题(因为它应该返回一个数字)和所有现有的解决方案(至少是示例)来看,列表看起来是唯一的。对于这种情况,我认为我们可以sum整个数组,然后用这些数字之间的期望总和减去即可生成输出。

N个自然数之和

1 + 2 + ....... + i + ... + n我们可以通过n * (n+1) / 2

进行评估

现在假设在我们的数组中,最小值为i,最大值为n

因此,我们可以评估i + (i+1) + ..... + n

A = 1 + 2 + ..... + (i-1) + i + (i+1) + .... n(即n*(n+1)/2

B = 1 + 2 + ..... + (i-1)

C = A - B将给我们( i +(i + 1)+ ... + n

现在,我们可以迭代一次数组并评估实际的总和(假设D),而C - D将为我们提供缺失的数字。

让我们首先在每个步骤中都创建相同的内容(对于性能而言并非最佳,但更具可读性),然后我们将尝试在单个迭代中完成

let input1 = [2, 3, 1, 5],
    input2 = [2, 3, 1, 5, 4, 6, 7, 9, 10],
    input3 = [3, 4, 5, 6, 8];

let sumNatural = n => n * (n + 1) / 2;

function findMissing(array) {
  let min = Math.min(...array),
      max = Math.max(...array),
      sum = array.reduce((a,b) => a+b),
      expectedSum = sumNatural(max) - sumNatural(min - 1);
      return expectedSum - sum;
}

console.log('Missing in Input1: ', findMissing(input1));
console.log('Missing in Input2: ', findMissing(input2));
console.log('Missing in Input3: ', findMissing(input3));

现在,让我们尝试在单个迭代中完成所有操作(因为我们对maxminsum进行了3次迭代)

let input1 = [2, 3, 1, 5],
    input2 = [2, 3, 1, 5, 4, 6, 7, 9, 10],
    input3 = [3, 4, 5, 6, 8];

let sumNatural = n => n * (n + 1) / 2;

function findMissing(array) {
  let min = array[0],
      max = min,
      sum = min,
      expectedSum;
  // assuming the array length will be minimum 2
  // in order to have a missing number
  for(let idx = 1;idx < array.length; idx++) {
    let each = array[idx];
    min = Math.min(each, min); // or each < min ? each : min;
    max = Math.max(each, max); // or each > max ? each : max;
    sum+=each; 
  }

  expectedSum = sumNatural(max) - sumNatural(min - 1);
  return expectedSum - sum;
}

console.log('Missing in Input1: ', findMissing(input1));
console.log('Missing in Input2: ', findMissing(input2));
console.log('Missing in Input3: ', findMissing(input3));

答案 3 :(得分:0)

如果数组为items,而缺失diff和当前const missingItem = items => [Math.min(...items)].map(min => items.filter(x => items.indexOf(x-diff) === -1 && x !== min)[0]-diff)[0] 之间的差为1:

O(n^2)

将给出([Math.min(...items)].map(min => items.filter(x => items.indexOf(x-diff) === -1 && x !== min))[0]).map(x => x-diff) 的复杂度。

它转换为:找到最小值,并检查数组中每个值n是否都没有n-diff值成员,这也不是最小值。对于所有尺寸差异不大的物品,都应为真。

要查找多个缺少的元素:

O((m^2)(n^2))

将提供m,其中some是缺少的成员数。

答案 4 :(得分:0)

发现了这个古老的问题,并想对此采取行动。我与https://stackoverflow.com/users/2398764/koushik-chatterjee有类似的想法,我想您可以通过知道总是只有一个缺少的元素来优化这一点。使用类似的方法但不使用最大值将导致以下结果:

function getMissing(arr) {
    var sum = arr.reduce((a, b) => a + b, 0);
    var lowest = Math.min(...arr);
    var realSum = (arr.length) * (arr.length + 1) / 2 + lowest * arr.length;
    return realSum - sum + lowest;
}

使用与上述相同的输入。我在几个浏览器的jsperf中运行了它,它的速度比其他答案要快。

https://jsperf.com/do-calculation-instead-of-adding-or-removing

首先将所有内容相加,然后计算最小值,然后计算整数的和(如果恰好是最小值)。因此,举例来说,如果我们有2,3,4,5,并且想要对它们求和,这与对0,1,2,3进行求和,然后加上最低数+在这种情况下为2 * 4,因为{{1} }将其恢复为原始。之后,我们可以计算出差异,但必须再次将其最小化。为了抵消这种变化,我们做了。

答案 5 :(得分:0)

您也可以使用while循环,如下所示-

function getMissing(array) {
  var tempMin = Math.min(...array);
  var tempMax = tempMin + array.length;
  var missingNumber = 0;
  
  while(tempMin <= tempMax){
    if(array.indexOf(tempMin) === -1) {
       missingNumber = tempMin;
    }
    tempMin++;
  }
  return missingNumber;
}

console.log(getMissing([2, 3, 1, 5]));
console.log(getMissing([2, 3, 1, 5, 4, 6, 7, 9, 10]));
console.log(getMissing([3, 4, 5, 6, 8]));

答案 6 :(得分:0)

我的方法是基于 O(N) 数组的就地排序,并且不使用任何其他数据结构。

  1. 找到数组中的最小元素。
  2. 就地排序。
  3. 再次循环数组并检查是否有任何元素放错位置,这就是答案!

function getMissing(ar) {

    var mn = Math.min(...ar);
    var size = ar.length;

    for(let i=0;i<size;i++){
        let cur = ar[i];
        // this ensures each element is in its right place
        while(cur != mn +i && (cur - mn < size) && cur != ar[cur- mn]) {
            // swap
            var tmp = cur; 
            ar[i] = ar[cur-mn];
            ar[cur-mn] = tmp;
        }
    }

    for(let i=0; i<size; i++) {
        if(ar[i] != i+mn) return i+mn;
    }

}

console.log(getMissing([2, 3, 1, 5]));
console.log(getMissing([2, 3, 1, 5, 4, 6, 7, 9, 10]));
console.log(getMissing([3, 4, 5, 6, 8]));