我有一个正整数的数组/字典(HashMap)。 我需要找到绝对差值大于或等于给定数量K的对的数量。
import random
import time
#given number
k = 4
# List of 2,00,000 random numbers in range 0-1000
strength = [random.randrange(0,1000) for x in range(200000)]
strength.sort()
# start clock
start1 = time.clock()
n = len(strength)
# count keeps track of number of pairs found
count = 0
for x in range(n):
for y in range(x,n):
if abs(strength[x] - strength[y]) >= k:
# if found, all number from this point to the end will satisfy
count += n-y
# So no need to go to the end
break
end1 = time.clock()
print(count)
print(end1-start1)
我找到的所有答案都是针对小于或等于给定数字的对。
我需要找到绝对差值大于或等于给定数量K的对的数量。
答案 0 :(得分:1)
您可以获取数组的2项组合,然后根据差异过滤/减少它们。
有人可能会在JavaScript中完成以下任务;
Array.prototype.combinations = function(n){
return this.reduce((p,c,i,a) => p.concat(n > 1 ? a.slice(i+1).combinations(n-1).map(e => (e.push(c),e))
: [[c]]),[]);
};
function getAcordingToDiff(a,d){
return a.combinations(2)
.reduce((p,c) => Math.abs(c[0]-c[1]) >= d ? (p.push(c),p) : p ,[]);
}
var arr = Array(30).fill().map((_,i) => i+1); // array from [1,...,30]
console.log(JSON.stringify(arr))
console.log(JSON.stringify(getAcordingToDiff(arr,25))); // diff >= 25
<强>解释强>
所以上面代码的核心显然是Array.prototype.combinations
函数。对于那些不熟悉JS的人来说,这只是我们在Array对象的原型下定义的一个普通函数(所以现在每个数组都可以访问这个函数,如arr.combinations(n)
)但是让我们使用更具表现力的语言和重构将上面的组合方法组合成一个通用函数。
function combinations(a,n){
var sa;
return a.reduce(function(p,c,i,a){
if (n > 1) sa = combinations(a.slice(i+1), n-1).map(e => (e.push(c),e));
else sa = [[c]];
return p.concat(sa);
},[]);
}
因为您会注意到combinations(a,n)
是一个递归函数,它接受数组a
和项目计数n
。它的工作原理是保留输入数组的第一项,并使用一个较短的数组combinations(a.slice(i+1), n-1)
递归调用自身,并减少一个项目,直到n
递减到1,在这种情况下它使用输入数组中的任何剩余开始它的返回周期,每个项目都包含在一个数组sa = [[c]]
中。
因此,在递归调用的返回周期中,我们获取结果数组并将保留的第一个元素(记住 - &gt;它在保持输入数组的第一项的基础上工作)推送到返回数组的每个项目中(记住 - &gt; ...并且每个项目都包含在一个数组sa = [[c]]
)中。
就是这样......你应该能够弄清楚自己的细节。
然而,在我们的应用程序中,我们获得了一系列数字,并要求仅获得具有一定差异的2个项目组合。在这种特殊情况下,我们不需要计算所有组合,然后过滤它们。我们可以在构建组合的过程中做到这一点。随着所需的差异值d
越来越大,这将比过滤后方法带来巨大的收益,因为现在随着d
越来越大,我们正在消除越来越多的两个项目组合,甚至在我们生成之前他们。并且......让我们硬编码我们的代码只处理2个项目并将所有内容合并到一个函数中。绩效结果如下;
function getCombosWithDiff(a, d, n = 2){
var sa;
return a.reduce(function(p,c,i,a){
if (n > 1) sa = getCombosWithDiff(a.slice(i+1), d, n-1).reduce((r,e) => Math.abs(e[0]-c) > d ? (e.push(c),r.push(e),r)
: r, []);
else sa = [[c]];
return p.concat(sa);
},[]);
}
var arr = Array(100).fill().map((_,i) => i+1);
result = getCombosWithDiff(arr,89);
console.log(JSON.stringify(arr));
console.log(JSON.stringify(result));
就是这样。我已经尝试了上面的代码列出了两个项目组合,每个组合的diff大于10,来自1000个项目的数组。 Chrome需要5000毫秒,FF需要14000毫秒。然而,如上所述,diff值d
越大,所需的时间越短。例如,使用差异900的相同阵列将在仅使用Chrome的1100毫秒和使用FF的4000毫秒内解析。
您可以测试并播放here
答案 1 :(得分:0)
请注意,对的总数为n * (n - 1) / 2
,因此,如果您可以找到差异小于K
的对数,则差异大于K
的对数是只是n * (n - 1) / 2 - num_pairs_with_diff_less_than_K
您提供的解决方案也是正确的(并且有详细记录)。如果您的问题是如何使其适应您的情况,那么您需要做的就是使用HashMap
(已排序)而不是strength
数组的值。
答案 2 :(得分:0)
创建一个初始化为零的整数的1001元素数组A.生成随机整数,并为每个这样的整数将适当的索引递增1。通过一些数学计算,你可以在不产生2,000,000个随机整数的情况下做到这一点,但这并不值得复杂。
创建第二个1001元素整数B s.t. B [i] = A [0] + ... + A [i]
答案是从i = 0到1000-k的B [i] *(2,000,000 - B [i + k-1])
的总和