给定一个数组,计算总和为60的倍数的对

时间:2019-01-13 19:43:47

标签: javascript algorithm time-complexity big-o

给定一个数组,如何找到加起来为60或被60整除的对数(两个值)。注意:必须比O(N ^ 2)快。

输入:[10、50、30、90] 输出2 推理:10 + 50 = 60,30 + 90 = 120(120被60整除)

输入:[60,60,60] 输出3 推理:60 + 60 = 120,60 + 60 = 120,60 + 60 = 120

我下面的代码将在O(N)时间中运行,但是我不知道如何处理彼此相等的对(即,如果数组中有2 30个值,它们将加1到您的计数器,但如果数组中有3 30个值,则会将3加到您的计数器上)。我以为我应该创建一个组合函数(即2C2或3C2),但这是一个线性函数,难道不只是使函数回到O(N ^ 2)?

values(myList) {
    var obj = {};
    var count = 0;

    // loop through array and mod each value and insert it into a dictionary
    myList.forEach((elem, index) => {
        if (!obj.hasOwnProperty(elem % 60)) {
            obj[elem % 60] = 1;
        } else {
            obj[elem % 60]++;
        }
    });

    for (var keys in obj) {
        if (obj.hasOwnProperty(60 - keys)) {
            if (60 - keys == keys) {
                // take care of pairs
                // obj[keys] = x --> xC2
            } else {
                count += Math.min(obj[keys], obj[60 - keys]);
                delete obj[keys]
                delete obj[60 - keys];
            }
        }
    }
    return count;
}

4 个答案:

答案 0 :(得分:1)

不需要任何组合。这是简单的数学运算。

它是n * (n-1) / 2

假设您有4个项目abcd

对将是:

  • (a,b)
  • (a,c)
  • (a,d)
  • (b,c)
  • (b,d)
  • (c,d)

对于 4 个项目,我们有 4 * 3/2 = 6

#UPDATE:

更改

count += Math.min(obj[keys], obj[60 - keys]);

count += obj[keys] * obj[60 - keys];

考虑2个键-1248

  • 12的元素-12,72,132
  • 48具有元素-48,108

从技术上讲,您要存储它们的计数,即3和2。 如果您观察,则总数为。我们可以制作的对的数量是 3 * 2 = 6 ,而不是Math.min(3,2);

答案 1 :(得分:1)

您可以在 O (1)时间内计算 n C2,因为 n C2 = n / n −2)!·2!= n ·( n -1)·( n −2)! / n −2)!·2! = n ·( n −1) / 2! ́ = n ·( n −1) / 2

也就是说,您可能需要考虑一种不同的方法:您可以在构建{时将其添加到count中,而不用基于obj来计算count的单独循环{1}}。这可能更直观,因为它消除了特殊情况的需要。 (由您决定。)

偶然地,您的obj测试不正确;将会检测到if (60 - keys == keys)的情况,但不会检测到keys == 30的情况。 (可能还需要解决其他一些错误。)

答案 2 :(得分:0)

更新:此解决方案为n ^ 2,因此无法回答原始问题。

let values = [60,10,20,50,40,30, 120, 60, 10];

let count = 0;

for (let i = 0; i < values.length; i++){
    for (let j = i+1; j < values.length; j++){
        let v = values[i] + values[j];
        if (v == 60 || !(v % 60)){
            count++;
        }
    }    
}

更新2:

要使其成为n + n * log(n),可以使用mod值创建一棵排序树,然后遍历每个mod值并查找60个mod值以查找组成对的数量区别。可以优化节点,并存储重复次数。这样可以解决您的问题吗?

答案 3 :(得分:0)

如果我们用目前为止看到的数字来计算每个元素可以组成的对,那么我们可以使用简单的加法运算,而不用管理组合运算或微妙的边缘情况。

function f(A, m){
  const rs = new Array(m+1).fill(0);
  for (let x of A){
    if (rs[(m - x % m) % m])
      rs[m] += rs[(m - x % m) % m];
    rs[x % m]++;
  }
  return rs[m];
}

console.log(f([10, 50, 30, 30], 60));
console.log(f([30, 10, 50, 30, 30], 60));
console.log(f([1, 5, 3, 3, 6, 24], 6));

(顺便说一句,我不确定为什么要区分两个数之和,它们之和等于60,而对的值之和可被60整除,因为前者包含在后者中。)