是否有找到两个范围之间重叠的有效方法?
实际上,两个范围标记为(a-c)和(b-d),并且我假设(c> a)&& (d> b)。
(b <= a <= d) which means if ((a >= b) && (d > a))
(b <= c <= d) which means if ((c >= b) && (d >= c))
(a <= b <= c) which means if ((b > a) && (c > b))
(a <= d <= c) which means if ((d > a) && (c > d))
但它永远不会结束,因为通过这种方式我当时只能找到一个范围,而且每个范围内我都必须检查其他情况。
例如,如果第一个条件(1)正确,我知道范围的开始发生了什么(a)我仍然需要检查其他条件的结束(c)。
更不用说所有这些都适用于(c&gt; a)&amp;&amp; (d> b),并且其中一个不等于另一个。
答案 0 :(得分:22)
在两种基本情况之一中,两个范围重叠:
相反,只有当每个范围的端点都不包含在其他范围内时,它们才会不重叠(图中的情况11和12)。我们可以检查两个范围的低端是否超过另一个范围的高端,以检测这两种情况:
if (a > d || c < b) {
// no overlap
}
else {
// overlap
}
我们可以反转条件,然后使用DeMorgan的法律来交换订单,如果这是更可取的:
if (a <= d && c >= b) {
// overlap
}
else {
// no overlap
}
要找到实际的重叠范围,您需要取两个低端的最大值,以及两个高端的最小值:
int e = Math.max(a,b);
int f = Math.min(c,d);
// overlapping range is [e,f], and overlap exists if e <= f.
以上所有假设范围包含,即a
和c
定义的范围包括a
的值和值c
。然而,调整专属范围是相当简单的。
答案 1 :(得分:3)
使用apache commons Range及其子类,尤其是overlap method。
答案 2 :(得分:1)
让我们让范围更清晰:
(start1, end1)
和(start2, end2)
Double totalRange = Math.max(end1, end2) - Math.min(start1, start2);
Double sumOfRanges = (end1 - start1) + (end2 - start2);
Double overlappingInterval = 0D;
if (sumOfRanges > totalRange) { // means they overlap
overlappingInterval = Math.min(end1, end2) - Math.max(start1, start2);
}
return overlappingInterval;
答案 3 :(得分:0)
设置x = max(a,b),y = min(c,d)。如果x < y(或x≤y)则(x-y)是两个范围的共同部分(在x = y的情况下退化),否则它们不重叠。
答案 4 :(得分:0)
检查重叠(只是真/假)实际上非常简单:
假设范围[a,b]和[c,d]。
如果符合以下条件,则会有重叠:a <= d
和b => c
。这也适用于a = b
和/或c = d
。
如果您有重叠,则重叠范围为[max(a,c),min(b,d)]
。
答案 5 :(得分:0)
根据这个问题的其他一些答案,我编写了以下两个代码示例:
第一个只会返回一个布尔值,表示两个范围是否重叠:
// If just a boolean is needed
public static boolean overlap(int[] arr1, int[] arr2) {
if((arr1[0] <= arr2[arr2.length - 1]) && (arr2[arr1.length - 1] >= arr2[0])) {
return true;
} else {
return false;
}
}
在存在重叠的情况下,第二个将返回重叠值的整数数组。否则它将返回一个空数组。
// To get overlapping values
public static int[] overlap(int[] arr1, int[] arr2) {
int[] overlappingValues = {};
if((arr1[0] <= arr2[arr2.length - 1]) && (arr2[arr1.length - 1] >= arr2[0])) {
int z = 0;
for(int a : arr1) {
for(int b : arr2) {
if(a == b) {
overlappingValues[z] = a;
z = z + 1;
}
}
}
} else {
return {};
}
}
希望这有帮助。
答案 6 :(得分:0)
根据更新后的问题,我通过Google做了一些研究,可以找到这个帖子:
Java, find intersection of two arrays
据我所知,它应符合给定的要求。并且所使用的代码片段很短,而且据我所知也很好。
考虑到离散值和连续值的评论,我想添加另一个可以找到的连续范围的潜在解决方案:
https://community.oracle.com/thread/2088552?start=0&tstart=0
此解决方案不直接返回重叠范围,但提供了一个有趣的类实现来进行范围比较。
答案 7 :(得分:0)
您可以使用修改后的circular collision detection算法检测两个范围的碰撞。
import java.util.Arrays;
public class RangeUtils {
public static void main(String[] args) {
int[] rangeA = { 10, 110 };
int[] rangeB = { 60, 160 };
int[] rangeC = intersectingRange(rangeA, rangeB);
System.out.println("Range: " + Arrays.toString(rangeC)); // Range: [60, 110]
}
// Based on circular collision detection.
public static boolean collisionDetected(int[] rangeA, int[] rangeB) {
int distA = Math.abs(rangeA[1] - rangeA[0]) / 2;
int distB = Math.abs(rangeB[1] - rangeB[0]) / 2;
int midA = (rangeA[0] + rangeA[1]) / 2;
int midB = (rangeB[0] + rangeB[1]) / 2;
return Math.sqrt((midB - midA) * (midB - midA)) < (distA + distB);
}
public static int[] intersectingRange(int[] rangeA, int[] rangeB) {
if (collisionDetected(rangeA, rangeB)) {
return new int[] {
Math.max(rangeA[0], rangeB[0]),
Math.min(rangeA[1], rangeB[1])
};
}
return null;
}
}
以下是代码的可视化示例;移植到JavaScript。
var palette = ['#393A3F', '#E82863', '#F6A329', '#34B1E7', '#81C683'];
var canvas = document.getElementById('draw');
var ctx = canvas.getContext('2d');
var rangeA = [10, 110];
var rangeB = [60, 160];
var rangeC = intersectingRange(rangeA, rangeB);
var collisionText = 'Range: [' + rangeC + ']';
var leftOffset = 18;
var topOffset = 24;
drawLines(ctx, [rangeA, rangeB], topOffset);
drawText(ctx, collisionText, leftOffset, topOffset);
drawBoundry(ctx, rangeC, topOffset);
// Based on circular collision detection.
function collisionDetected(rangeA, rangeB) {
var distA = Math.abs(rangeA[1] - rangeA[0]) / 2;
var distB = Math.abs(rangeB[1] - rangeB[0]) / 2;
var midA = (rangeA[0] + rangeA[1]) / 2;
var midB = (rangeB[0] + rangeB[1]) / 2;
return Math.sqrt((midB - midA) * (midB - midA)) < (distA + distB);
}
function intersectingRange(rangeA, rangeB) {
if (collisionDetected(rangeA, rangeB)) {
return [Math.max(rangeA[0], rangeB[0]), Math.min(rangeA[1], rangeB[1])];
}
return null;
}
function drawText(ctx, text, x, y) {
ctx.save();
ctx.font = '18px Arial';
ctx.fillText(text, x, y);
ctx.restore();
}
function drawLines(ctx, lines, topOffset) {
topOffset = topOffset || 0;
var sizeWidth = ctx.canvas.clientWidth;
var sizeHeight = ctx.canvas.clientHeight - topOffset;
var yOffset = sizeHeight / (lines.length + 1);
for (var i = 0; i < lines.length; i++) {
var color = palette[i % palette.length];
var yPos = (i + 1) * yOffset + topOffset;
drawLine(ctx, lines[i], yPos, color)
}
}
function drawLine(ctx, range, index, color) {
ctx.save();
ctx.beginPath();
ctx.moveTo(range[0], index);
ctx.lineTo(range[1], index);
ctx.strokeStyle = color;
ctx.lineWidth = 4;
ctx.stroke();
ctx.restore();
}
function drawBoundry(ctx, bounds, topOffset) {
var sizeHeight = ctx.canvas.clientHeight - topOffset;
var padding = sizeHeight * 0.25;
var y1 = topOffset + padding;
var y2 = sizeHeight + topOffset - padding;
ctx.save();
ctx.beginPath();
ctx.strokeStyle = palette[4];
ctx.setLineDash([5, 5]);
ctx.lineWidth = 2;
ctx.rect(bounds[0], y1, bounds[1] - bounds[0], sizeHeight * 0.5);
ctx.stroke();
ctx.restore();
}
&#13;
canvas#draw {
background: #FFFFFF;
border: thin solid #7F7F7F;
}
&#13;
<canvas id="draw" width="180" height="160"></canvas>
&#13;