我有一系列范围,我希望能够找到所有重叠范围:
var examples = [
// Group 1
{start: 9, end: 10.50}, // Range 1
{start: 10, end: 10.50}, // Range 5
// Group 2
{start: 11, end: 13}, // Range 2
{start: 13.5, end: 14.5}, // Range 3
{start: 11.5, end: 14} // Range 4
]
答案 0 :(得分:4)
以下是我的观点:
var examples = [
{start: 17, end: 20},
{start: 9, end: 10.50},
{start: 15, end: 17},
{start: 11, end: 12},
{start: 18, end: 19.5},
{start: 19.5, end: 22},
{start: 11.5, end: 12.5},
{start: 11.5, end: 13},
{start: 17.5, end: 18.5},
{start: 19, end: 19.5},
{start: 22, end: 25}
]
function partitionIntoOverlappingRanges(array) {
array.sort(function (a,b) {
if (a.start < b.start)
return -1;
if (a.start > b.start)
return 1;
return 0;
});
var getMaxEnd = function(array) {
if (array.length==0) return false;
array.sort(function (a,b) {
if (a.end < b.end)
return 1;
if (a.end > b.end)
return -1;
return 0;
});
return array[0].end;
};
var rarray=[];
var g=0;
rarray[g]=[array[0]];
for (var i=1,l=array.length;i<l;i++) {
if ( (array[i].start>=array[i-1].start)
&&
(array[i].start<getMaxEnd(rarray[g]))
) {
rarray[g].push(array[i]);
} else {
g++;
rarray[g]=[array[i]];
}
}
return rarray;
} // end partitionIntoOverlappingRanges
上述examples
的结果
答案 1 :(得分:2)
这是一个简单的扫描算法。它在O(n log n)中执行,因为必须对范围进行排序。
基本思路是从左向右扫描,查找起点和终点(需要每个点的排序列表)。扫描时,跟踪活动范围的数量(即,遇到起点并且尚未遇到其端点的范围)。每次到达起点时,都需要将范围添加到当前组。通过在每个起始点递增它并在每个终点递减它来维持范围计数。每次计数返回0时,都会找到一个完整的组。
如果要计算简化的范围集而不是组,则可以简化。当有效范围计数从0递增到1时,不设置组中的一组范围,而是设置当前组合组的起始点,当有效范围计数从1递减到0时,设置结束点。在这种情况下,您只需要一个起始点的排序列表和一个排序的终点列表(在所示的算法中,通过按起点对范围本身进行排序来找到排序的起始点。需要该组以便范围可以被添加到累积组。)
按照起始值对范围进行排序。
列出结束值并对其进行排序(不必知道哪个范围属于端点)。调用此end_values。
将current_group初始化为空集,并将active_range_count初始化为0.将current_range和current_end初始化为0.
循环直到完成:
如果current_range是范围和范围的有效索引[current_range] .start小于end_values [current_end]:
否则,如果current_end是end_values的有效索引:
否则,完成。
以下是javascript中的两个版本:
/* Partition an array of ranges into non-overlapping groups */
/* Side-effect: sorts the array */
function partition(ranges) {
var end_values = ranges.map(function(r){return r.end}).sort(function(a, b){return a - b})
ranges.sort(function(a, b){return a.start - b.start})
var i = 0, j = 0, n = ranges.length, active = 0
var groups = [], cur = []
while (1) {
if (i < n && ranges[i].start < end_values[j]) {
cur.push(ranges[i++])
++active
} else if (j < n) {
++j
if (--active == 0) {
groups.push(cur)
cur = []
}
} else break
}
return groups
}
/* Given a array of possibly overlapping ranges, produces
* an array of non-overlapping ranges covering the same
* values.
*/
function compose_ranges(ranges) {
var starts = ranges.map(function(r){return r.start}).sort(function(a, b){return a - b})
var ends = ranges.map(function(r){return r.end}).sort(function(a, b){return a - b})
var i = 0, j = 0, n = ranges.length, active = 0
var combined = []
while (1) {
if (i < n && starts[i] < ends[j]) {
if (active++ == 0) combined.push({start: starts[i]})
++i
} else if (j < n) {
if (--active == 0) combined[combined.length - 1].end = ends[j]
++j
} else break;
}
return combined
}
答案 2 :(得分:0)
概念很简单:记录每个特定组的最大范围。
点击下面的代码。
function contains(range, number) {
return number > range.start && number < range.end
}
function partitionIntoOverlappingRanges(array) {
var groups = [];
for (var i = 0; i < array.length; i++) {
for (var j = 0; j < groups.length; j++) {
if (contains(groups[j], array[i].start) || contains(groups[j], array[i].end)) {
groups[j].arrays.push(array[i]);
if (groups[j].start > array[i].start) groups[j].start = array[i].start;
if (groups[j].end < array[i].end) groups[j].end = array[i].end;
break;
}
}
if (j == groups.length) {
groups.push({
start: array[i].start,
end: array[i].end,
arrays: [array[i]]
})
}
}
return groups
}