给定一个数组,如何找到加起来为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;
}
答案 0 :(得分:1)
不需要任何组合。这是简单的数学运算。
它是n * (n-1) / 2
。
假设您有4个项目a
,b
,c
,d
。
对将是:
对于 4 个项目,我们有 4 * 3/2 = 6 。
#UPDATE:
更改
count += Math.min(obj[keys], obj[60 - keys]);
到
count += obj[keys] * obj[60 - keys];
考虑2个键-12
和48
。
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整除,因为前者包含在后者中。)