//如何在一组线段中快速找到有重叠的部分
var crossResult = (function getCrossInterval(intervalArray){
var result = [];
var tree = [];
//将所有线段写到树中,这里用数组处理免去了排序的步骤,以线段的最小值作为key避免了组内比较因为都是包含关系,以线段长度作为key是为了方便比较出结果后取出相应数据
intervalArray.forEach(function(v,k){
var length = v[1] - v[0],item;
!tree[v[0]] ? item = [] : item = tree[v[0]];
item[length] = v;
tree[v[0]] = item;
});
//获取树中的key
var keys = [];
tree.forEach(function(v,k){
keys.push(k);
});
//计算key的个数
var treeLength = keys.length;
//最外层循环到n-1为止因为最后一组线段不需要主动和别人比较
first:for(var i = 0;i < treeLength - 1;i++){
var sub = tree[keys[i]];
var subKeys = [];
sub.forEach(function(item,index){
subKeys.push(index);
});
var subLength = subKeys.length;
//循环叶子节点,取每一个线段和其他组的线段比较
second:for(var j = 0;j < subLength;j++){
//被比较的循环从i+1开始 不需要查找以前的数据
thred:for(var k = i + 1;k < treeLength;k++){
//获取被比较线段数组的最小值(对应的key值)
var comparedMin = keys[k];
//获取被比较线段组
var comparedSub = tree[comparedMin];
//计算被比较数组的长度
var comparedSubLength = comparedSub.length;
if(sub[subKeys[j]][1] < comparedMin){
//如果被比较线段的最小值大于比较线段的最大值说明没有落在比较线段的区间中,以后的数据都不用比较了,因为是升序排列,所以直接跳到最外层循环
continue second;
}else if(sub[subKeys[j]][1] == comparedMin){
//如果被比较线段的最小值等于比较线段的最大值说明两个区间只有一个交叉点,取出这组所有的数据,作为结果,以后的数据都不用比较了,因为是升序排列,所以直接跳到最外层循环
comparedSub.forEach(function(v1,k1){
var combine = [sub[subKeys[j]],v1];
result.push(JSON.stringify(combine));
});
continue second;
}else{
//如果被比较线段的最小值小于比较线段的最大值说明该线段的最小值落在了比较线段区间中,需要计算最大值是否在区间外,才能形成交叉
//如果要最大值落在区间外,被比较线段的最大值的最小取值应该是比较线段的最大值+1
var min = sub[subKeys[j]][1] + 1;
//形成交叉的最小长度
var minLength = min - comparedMin;
//循环被比较数组,找出长度大于等于minLength的元素即为可与比较数组形成交叉的线段
var crossArray = comparedSub.filter(function(v2,k2){
return k2 >= minLength;
});
crossArray.forEach(function(v3,k3){
var combine = [sub[subKeys[j]],v3];
result.push(JSON.stringify(combine));
});
}
}
}
}
return result;
})([
[2,5],
[3,7],
[3,6],
[5,8],
[2,7],
[1,3],
[4,7],
[2,9],
[1,6],
[1,5],
[3,9],
[2,8],
[2,9],
[3,11],
[1,8],
[4,6]
]);
console.log(crossResult);