如何找到两个给定范围之间的重叠?

时间:2016-03-16 11:58:59

标签: java

是否有找到两个范围之间重叠的有效方法?

All cases tha possible

实际上,两个范围标记为(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),并且其中一个不等于另一个。

8 个答案:

答案 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.

以上所有假设范围包含,即ac定义的范围包括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;

基于this answer

答案 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 <= db => 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。

&#13;
&#13;
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;
&#13;
&#13;