编辑:由于@Bergi和@MattEllen的先前评论,我的思想有所进步,因此我重新发布了这个问题。
假设我们有两个具有重复值的排序列表
// here arr1.length = arr2.length = 16
ar11 = 0 0 0 0 1 1 1 1 2 2 2 2 3 3 4 5
arr2 = 0 0 1 1 1 1 2 2 2 2 3 4 5 6 7 8
我们要计算它们的交点(isect)
// duplicates preserved !
isect = 0 0 1 1 1 1 2 2 2 2 3 4 5
我们可以使用根据Intersection of two lists including duplicates?
中所述的Python版本改编的简单线性算法// basic intersection code
// allows lists to handle duplicates
const dumb_intersect = (arrays, intervals, params) => {
const { arr1, arr2, results } = arrays
const { matches} = params
const { i1, i2 } = intervals
ii_iterate(arr1, i1, (value, rank) => {
const count = matches.get(value) || 0
matches.set(value, count + 1)
})
ii_iterate(arr2, i2, (value, rank) => {
const count = matches.get(value) || 0
if(count > 0) {
results.push(value)
if (count > 1) {
matches.set(value, count - 1)
} else {
matches.delete(value)
}
}
})
}
在此示例中:
为简单起见,我给您ii_iterate的代码:
// apply a callback function to each element of a slice of an array
const ii_iterate = (arr, ii, callback) => {
return arr.slice(ii.min, ii.max + 1).map((val, idx) => {
return callback(val, idx)
})
}
TL:DR; ;-)
所有这些东西都是很棒的,但是我认为我可以做得更好,更快!
特别是如果我们对间隔的割除进行二进位(二分频)的序列,直到阈值:
// THRESOLD = 4 elements
cuts[0]: [0..15] # 1 interval * 16 elements
cuts[1]: [0..7] [8..15] # 2 * 8
cuts[2]: [0..3] [4..7] [8..11] [12..15] # 4 * 4
...并仅应用重叠间隔的dumb_intersect
通常,对于庞大的列表,阈值的计算很容易:
thresold = 1 + Math.floor(Math.log((1 + arr1.length) * (1 + arr2.length)))
N = 1000 thresold = 15
N = 1000000 thresold = 28
但这是问题的次要方面。 Bianry拆分过程也很容易做到。初始示例的Arr1和Arr2变为阈值4:
ar11 = 0 0 0 0; 1 1 1 1; 2 2 2 2; 3 3 4 5
arr2 = 0 0 1 1; 1 1 2 2; 2 2 3 4; 5 6 7 8
(请记住那可能是大列表)
这个问题似乎是两个间隔列表之间的“乌龟拉力赛车”:
由于dumb_intersect的复杂度为线性O(N),所以我今天不确定可以在O(log(N))或O(sqrt(N))中进行优化->因此,我将仅使用线性将来的编码版本!!
谢谢大家。
答案 0 :(得分:0)
还请注意,arr1和arr2是预先排序的列表,具有升序。
在这种情况下,分割间隔的所有麻烦是什么?我们只需要一个merge algorithm即可做到:
function intersection(arrays, intervals) {
const { arr1, arr2, results } = arrays
const { i1, i2 } = intervals
let i = i1.min, j = i2.min;
while (i <= i1.max && j <= i2.max) {
if (arr1[i] < arr2[j]) {
i++
} else if (arr1[i] > arr2[j]) {
j++
} else { // arr1[i] == arr2[j]
results.push(arr1[i])
i++
j++
}
}
}