找到“圆形”范围的重叠

时间:2015-02-28 01:33:45

标签: algorithm range

圆形是指一个范围可以越过最大值并从0开始循环返回。例如:

给出最大值:

9 

两个范围(两者都可以是"循环"):

0123456789
----range1 (a normal range)  
ge2----ran (a circular range)

计算交叉点的好算法是什么? 在这种情况下,交叉点将是:

7-9 
789
ge1
ran

可以"删除"的算法的奖励一个来自另一个。 通过删除我的意思是,一个范围正在从另一个范围中完全提取:

0123456789
----range1
ge2----ran

从范围1减去range2会产生:

3456
-ran

更新:数字总是整数。只有两个范围同时进行比较,但它们总是连续的,如上所述,它们可能会跨越0。

另请注意,如果一个范围完全包含另一个范围,则输出布尔值会很好。我想我可能有一个很好的方法。

谢谢!

2 个答案:

答案 0 :(得分:1)

看起来你可以简单地将你的范围中的每个离散元素都放在一个集合中。然后,您可以执行集合的交集以获取输出元素。

这可以通过使用哈希表在O(M + N)时间内完成。

遍历您的第一个范围,在哈希表中为每个元素创建一个条目,该元素是该范围的成员。

然后浏览第二个范围并查看每个元素。如果它已经在哈希表中,则它是范围交集的一部分。

稍加思考,你就会弄清楚设置差异是如何工作的。

如果您需要与第三个范围相交,请从表格中删除不属于第二个范围的元素。

答案 1 :(得分:0)

这是关于我如何解决上述问题的最新消息。基本上,战略是分而治之。

如果需要,两个范围都分为两个单独的部分。然后将它们与每一个进行比较。

希望这可以帮助某人,并告诉我你是否在这个策略中看到任何逻辑错误。之后我会发布"删除"我上面提到的算法。

另请注意,范围是从0开始的。

var arePositiveIntegers = require('./arePositiveIntegers');
//returns an array of the overlaps between two potentially circular ranges
module.exports = function getOverlapsOfPotentiallyCircularRanges(rangeA, rangeB, maxLength) {
  if (!arePositiveIntegers(rangeA.start, rangeA.end, rangeB.start, rangeB.end)) {
    console.warn("unable to calculate ranges of  inputs");
    return [];
  }
  var normalizedRangeA = splitRangeIntoTwoPartsIfItIsCircular(rangeA, maxLength);
  var normalizedRangeB = splitRangeIntoTwoPartsIfItIsCircular(rangeB, maxLength);

  var overlaps = [];
  normalizedRangeA.forEach(function(nonCircularRangeA) {
    normalizedRangeB.forEach(function(nonCircularRangeB) {
      var overlap = getOverlapOfNonCircularRanges(nonCircularRangeA, nonCircularRangeB);
      if (overlap) {
        overlaps.push(overlap);
      }
    });
  });
  return overlaps;
};

//takes a potentially circular range and returns an array containing the range split on the origin
function splitRangeIntoTwoPartsIfItIsCircular(range, maxLength) {
  if (range.start <= range.end) {
    //the range isn't circular, so we just return the range
    return [{
      start: range.start,
      end: range.end
    }];
  } else {
    //the range is cicular, so we return an array of two ranges
    return [{
      start: 0,
      end: range.end
    }, {
      start: range.start,
      end: maxLength - 1
    }];
  }
}

function getOverlapOfNonCircularRanges(rangeA, rangeB) {
  if (!arePositiveIntegers(rangeA.start, rangeA.end, rangeB.start, rangeB.end)) {
    console.warn("unable to calculate ranges of  inputs");
    return null;
  }
  if (rangeA.start < rangeB.start) {
    if (rangeA.end < rangeB.start) {
      //no overlap
    } else {
      if (rangeA.end < rangeB.end) {
        return {
          start: rangeB.start,
          end: rangeA.end
        };
      } else {
        return {
          start: rangeB.start,
          end: rangeB.end
        };
      }
    }
  } else {
    if (rangeA.start > rangeB.end) {
      //no overlap
    } else {
      if (rangeA.end < rangeB.end) {
        return {
          start: rangeA.start,
          end: rangeA.end
        };
      } else {
        return {
          start: rangeA.start,
          end: rangeB.end
        };
      }
    }
  }
}