Нахождение наибольшего промежутка между несколькими интервалами - PullRequest
4 голосов
/ 23 июня 2019

Представьте, что у вас есть переменная $ 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. Выполните цикл по массиву временной шкалы и запустите счетчик $, который увеличивается с каждым последующим «E».символов, затем сохраните его значение в переменной $ max, если оно больше предыдущего.

Какие улучшения можно сделать?

Обратите внимание:

  • Интервалы всегда сортируются относительно их начальных позиций.
  • Интервалы не должны начинаться с начала временной шкалы, а также не должны заканчиваться также и в конце временной шкалы.Таким образом, может быть разрыв до первого интервала и разрыв после последнего интервала.
  • Интервалы могут перекрываться.Так что простое вычисление начала следующего интервала минус конец этого интервала не сработает ... Рассмотрим пример: [1,5] [2,4] [6,10] [6,8]

Ответы [ 5 ]

1 голос
/ 23 июня 2019
<?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;
  • Поскольку ваши интервалы отсортированы по времени начала, мы создаем новый массив непересекающихся интервалов.
  • Теперь мы просто вычитаем новое время начала с предыдущим временем окончания и, наконец, последним временем окончания с самим $n и находим максимальный разрыв.
1 голос
/ 23 июня 2019

Обновленное решение: -

$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

0 голосов
/ 24 июня 2019

У нас может быть простой, 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`)
0 голосов
/ 23 июня 2019

Я описываю подход, который будет намного более эффективным -

  1. Если интервалы не отсортированы в соответствии с временем начала - сначала отсортируйте массив интервалов на основе времени начала.В худшем случае сложность O (nlogn).если он отсортирован, нам ничего не нужно делать.

  2. Итерация по отсортированному массиву интервалов из второго элемента и каждой итерации, если время начала больше, чем время окончания последнегоинтервал - рассчитать разницу.

  3. Узнайте максимальную разницу, сравнивая разницу в каждой итерации.

    Сложность - Несортированный массив - O (nlogn) + O (n) Сортированный массив - O (n).

псевдокод -

enter image description here

пример -

enter image description here

0 голосов
/ 23 июня 2019

Если разделы отсортированы (как в вашем примере). Вы можете перебирать разделы и создавать новый массив, содержащий:

  • Исходное положение интервала в первом массиве
  • Расстояние первого элемента раздела и последнего элемента предыдущего раздела.

С этим у вас будет список промежутков между разделами. Затем вы просто сортируете эти пробелы и берете последний.

Но, как я уже сказал, это предполагает, что ваши разделы отсортированы .

Есть пример, затем вы сортируете $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];
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...