找到多个间隔之间最长的间隔

时间:2019-06-23 10:24:27

标签: php arrays algorithm logic

想象一下,您有一个变量$ n表示时间轴上的多个分区,以及一个可变长度的间隔数组:

$n = 10;
$intervals = [
  [1, 2],
  [2, 2],
  [5, 6],
  [8, 10],
];

问题在于在时间线上找到这些间隔之间的最大差距。对于上述问题,我们有两个长度分别为2和1的间隙,因此答案应为2。为了更好地可视化它:

intervals visualization

我直接的方法效率不高...

  1. 初始化一个长度为$ n的空时间轴数组,将每个元素设置为'E',如空。
  2. 在每个间隔上进行Foreach循环,并从间隔开始到间隔结束创建另一个for循环,然后将时间轴数组中的那些元素设置为'T',如图所示。
  3. 在时间轴数组上循环,并启动一个$ counter,该计数器随每个连续的'E'字符递增,然后将其值保存到变量$ max中(如果它大于前一个)。

我可以做些什么改善?

请注意:

  • 间隔总是根据其开始位置进行排序。
  • 间隔不必从时间线的开头开始,也不必在时间线的结尾处结束。因此,第一个间隔之前可能有一个间隙,最后一个间隔之后可能有一个间隙。
  • 时间间隔可以重叠。因此,简单地计算下一个间隔的开始减去该间隔的结束将不起作用...请考虑以下示例:[1,5] [2,4] [6,10] [6,8]

5 个答案:

答案 0 :(得分:1)

更新的解决方案:-

$intervals = [
    [1,2],
    [2,2],
    [5,6],
    [8,10]
];
$rr = [];
foreach($intervals as $v){
    $rr[] = range($v[0],$v[1]);
}
$n = 10;
$range      = range(1,$n);
$diff =     array_diff($range,array_values(array_unique(array_merge(...$rr))));
$r = groupConsecutive($diff);

$max = 0;
if (count($r)) {
    foreach ($r as $gap) {
        $length = 1;
        if (is_array($gap)) $length = count($gap);
        if ($max < $length) $max = $length;
    }
}

echo $max;

function  groupConsecutive($array) {
   $ret  = array();
   $temp = array();
   foreach($array as $val) {
      if(next($array) == ($val + 1))
         $temp[] = $val;
      else
         if(count($temp) > 0) {
            $temp[] = $val;
            $ret[]  = $temp;
            $temp   = array();
         }
         else
            $ret[] = $val;
   }
   return $ret;
}

DEMO

答案 1 :(得分:1)

>>> consumer = KafkaConsumer('foo', 
...                          group_id='test-group',
...                          bootstrap_servers=['localhost:9092'])
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
  File "/usr/local/lib/python3.7/site-packages/kafka/consumer/group.py", line 353, in __init__
    self._client = KafkaClient(metrics=self._metrics, **self.config)
  File "/usr/local/lib/python3.7/site-packages/kafka/client_async.py", line 239, in __init__
    self.config['api_version'] = self.check_version(timeout=check_timeout)
  File "/usr/local/lib/python3.7/site-packages/kafka/client_async.py", line 865, in check_version
    raise Errors.NoBrokersAvailable()
kafka.errors.NoBrokersAvailable: NoBrokersAvailable
  • 由于您的时间间隔是根据开始时间排序的,因此我们制作了一个新的非重叠时间间隔数组。
  • 现在,我们只需将新的开始时间与上一个结束时间相减,最后也将最后的结束时间与<?php $n = 10; $intervals = [ [1, 2], [2, 2], [5, 6], [8, 10] ]; $non_overlapping = []; $start = -1; $end = -1; foreach($intervals as $index => $interval){ if($start == -1) $start = $interval[0]; if($end == -1) $end = $interval[1]; if($index == 0) continue; // since it's first index if($interval[0] >= $end){ $non_overlapping[] = [$start,$end]; $start = $interval[0]; $end = $interval[1]; }else{ $end = max($end,$interval[1]); } } $non_overlapping[] = [$start,$end]; $maximum_gap = 0; $prev_end = 0; foreach($non_overlapping as $index => $interval){ $maximum_gap = max($maximum_gap,$interval[0] - $prev_end - 1); $prev_end = $interval[1]; } $maximum_gap = max($maximum_gap,$n - $prev_end); echo $maximum_gap; 本身相减,即可找到最大的差距。

答案 2 :(得分:0)

如果分区已排序(例如您的示例)。您可以遍历分区并创建一个包含以下内容的新数组:

  • 第一个数组中间隔的原始位置
  • 该分区的第一个元素与上一个分区的最后一个元素之间的距离。

这样,您将获得分区之间的间隙列表。然后,您只需对这些差距进行排序,并消除最后一个差距。

但是正如我所说,这是假设您的分区是已排序

有一个示例,然后按值的第二个元素对$gaps进行排序,然后取最后一个。

<?php                                                                                                                                                                                                                                                         

$n = 10;
$intervals = [
  [1, 2],
  [2, 2],
  [5, 6],
  [8, 10],
];

$gaps = array();

$prev_range_max = 1;
for ($i = 0; $i < count($intervals); $i++) {
    $gaps[] = Array($i, $intervals[$i][0] - $prev_range_max);
    $prev_range_max = $intervals[$i][1];
}

答案 3 :(得分:0)

我描述的是一种高效的方法-

  1. 如果时间间隔未根据开始时间进行排序- 首先根据开始时间对间隔数组进行排序。 最坏情况下的复杂度O(nlogn)。如果已排序,则我们无需执行任何操作。

  2. 如果第二个元素的开始时间大于最后一个间隔的结束时间,则从第二个元素遍历排序的间隔数组,并进行每次迭代-计算差值。

  3. 找出最大差异,比较每次迭代中的差异。

    复杂度- 未排序的数组-O(nlogn)+ O(n) 排序数组-O(n)。

伪代码-

enter image description here

示例-

enter image description here

答案 4 :(得分:0)

我们可以有一个简单的O(n)时间O(1)空间算法,当我们迭代按起始位置排序的间隔时,可以跟踪我们所处的间隔。当前间隔开始于:

left = interval[0][0]
right = interval[0][1]
i = 1 // pointer
n = list length
max_gap = 0

然后

while i < n and interval[i][0] <= right:
  // update right
  right = max(right, interval[i][1])
  i = i + 1

现在,如果没有空缺,我们要么排在列表的末尾,要么我们处于至少从(right + 1)开始的新间隔中(我认为在您的情况下,该间隔将不被视为有空缺) )。

因此,这里更新当前的最大间隙并重复while例程。

max_gap = max(
  max_gap,
  interval[i][0] - right - 1
)
left = interval[i][0]
right = interval[i][1]

JavaScript示例:

function f(A){
  console.log(JSON.stringify(A))
  let left = A[0][0]
  let right = A[0][1]
  console.log(`i: 0, (${ left }, ${ right })`)
  let i = 1 // pointer
  let n = A.length
  let max_gap = 0

  while (i < n){
    while (i < n && A[i][0] <= right){
      // update right
      right = Math.max(right, A[i][1])
      console.log(`i: ${ i }, (${ left }, ${ right })`)
      i = i + 1
    }

    if (i < n){
      max_gap = Math.max(
        max_gap,
        A[i][0] - right - 1
      )
      console.log(`i: ${ i }, max_gap: ${ max_gap }`)
      left = A[i][0]
      right = A[i][1]
    }
  }

  return max_gap
}

let examples = [
  [[1,5], [2,4], [6,10], [6,8]],
  [[1, 2], [2, 2], [5, 6], [8, 10]],
  [[2,4], [5,8], [9,10]],
  [[1,1], [5,6], [9,10]]
]

for (let ex of examples)
  console.log(`result: ${ f(ex) }\n\n`)