PHP - Найти количество групп с учетом некоторых ограничений - PullRequest
1 голос
/ 24 сентября 2019

Учитывая n = 3 собаки и m = 3 пары врагов, a = [1, 2, 3] и b = [3, 3, 1], собака 1 является врагом собаки 3, а собака 3 являетсяВраг собак 1 и 2. Поскольку 3 является врагом как 1, так и 2, он должен находиться в своем собственном контейнере.Собаки 1 и 2 могут быть вместе или по отдельности.Существует 4 возможных группы: {1, 2}, {1}, {2}, {3}.Обратите внимание, что интервалы вдоль исходной линии собак пронумерованы последовательно от 1 до n, т.е. в этом случае [1, 2, 3].Собаки не могут быть переупорядочены, и собаки не могут быть пропущены, например, {2, 1} и {1, 3} являются недействительными.

Так, учитывая следующее:

дело № 1 :

n = 5
m = 2
a = (1,2)
b = (3,5)

Результат: Всего можно сформировать 11 групп.

case # 2

n = 8
m = 4
a = (2,3,4,3)
b = (8,5,6,4)

Результат:Всего можно сформировать 18 групп.


Вот мой код:

function countSubstrings($n, $a, $b) {
    $tokenArr = array(); 
    $x = 1;
    while ($x <= $n){
        $tokenArr[] = $x;
        $x++;
    }

    $first = 0;
    $last = $n - 1;
    $outArr   = array();
    $pointer  = 0;

    /* generate groups left to right */
    for ($i = $first; $i <= $last; $i++) {
        $outArr[$pointer][] = $tokenArr[$i];
        $tokenString = $tokenArr[$i];
        $pointer++; 
        for ($j = $i + 1; $j <= $last; $j++) {
            $tokenString .= $tokenArr[$j];
            $outArr[$pointer] = str_split($tokenString);
            $pointer++;
        }
    }

    /* find the enemeies */
    $intersects = array();
    for($k = 0; $k < count($outArr); $k++){
        if (count(array_intersect($outArr[$k], $a)) > 1 || count(array_intersect($outArr[$k], $b)) > 1) {
            $intersects[] = $outArr[$k];
        }
    }

    /* remove first and last items which are basically equal to $a and $b */
    $intersects = array_slice($intersects, 1, -1); 


    /* remove the enemeies from generated groups */
    foreach ($outArr as $keya => $valuea) {
        if (in_array($valuea, $intersects)) {
            unset($outArr[$keya]);
        }
    }

    return count($outArr);
}

Пока мой код работает в случае: # 1, но не на # 2.

1 Ответ

1 голос
/ 24 сентября 2019

Логика пересечения кажется мне неправильной, поскольку мы должны проверить, существует ли отношение, образованное [a , b], например, [1,2], в $outArr или нет.Текущая проверка count(array_intersect($outArr[$k], $a)) > 1 не заботится об этом.Он скорее проверяет, присутствует ли какой-либо элемент в $outArr[$k] в $a или нет.

Итак, измените текущую логику с:

/* find the enemeies */
    $intersects = array();
    for($k = 0; $k < count($outArr); $k++){
        if (count(array_intersect($outArr[$k], $a)) > 1 || count(array_intersect($outArr[$k], $b)) > 1) {
            $intersects[] = $outArr[$k];
        }
    }

    /* remove first and last items which are basically equal to $a and $b */
    $intersects = array_slice($intersects, 1, -1);

на

$intersects = array();
foreach($a as $index => $val1){
    $val2 = $b[$index];
    foreach($outArr as $current_group){
        if(in_array($val1,$current_group) && in_array($val2,$current_group)){ // check if both exist as they are enemies
            $intersects[] = $current_group;
        }
    }
}

Демонстрация: https://3v4l.org/Q2rnP

В приведенном выше коде мы:

  • перебираем все элементы $a и одновременно с $b с помощью $index в foreach.

  • Проверьте, подходит ли текущая группа в $outArr, как $a[$index] (он же $val1), так и $b[$index](иначе $val2) существуют в группе или нет.

  • Если оба существуют в текущей группе, мы помещаем их в пересечение, поскольку они являются врагами.Ваша остальная логика правильна.


Эффективное решение:

  • Мы должны использовать эту строку:

Группа определяется как интервал (x, y), так что все собаки в диапазоне от x до y образуют группу.

  • Это означает, что нам нужно смотреть на подмассивы (как вы правильно поняли) вместо подпоследовательностей.

  • Теперь мы делаем цикл от 1 до N, и если мы найдем число, у которого есть враг слева, мы можем сформировать только следующие группы из этого числа + 1и далее.Все, что перед ними, не может быть включено, так как мы смотрим на подмассивы.

  • Например, давайте предположим, что 5 - враг 3 в линии 1до 5 и других врагов нет.Итак, групповые формирования будут выглядеть следующим образом.

Представление:

  1   2   3   4   5 
 -1  -1   5  -1   3

  |___|
  |___|___|
  |___|___|___|
      |___|
      |___|___|
          |___|


              |___| // the connection/group (4,5) remains and breaks everything before 4 since 3 is an enemy of 5 and we are looking for subarrays. So everything before 4 is disconnected anyway.
  • Итак, наше следующее начальное животное/ собака, с которой нужно смотреть: 4.

  • Для каждого врага / животного мы поддерживаем ближайшего врага слева, если он присутствует.Если есть, мы обновляем следующее животное, чтобы искать группы, как доказано выше.В приведенном ниже коде $prev_start - это переменная, которая поддерживает следующее животное для просмотра.

  • Чтобы получить ближайшего врага слева для каждого животного, мы предварительно обрабатываем детали противника следующим образом:

Предварительная обработка:

$enemies = array_combine(range(1,$n),array_fill(0,$n,-1)); // nothing tricky, just generates an array filled with sequential numbers as keys and sets it's value as -1

   foreach($a as $index => $enemy_1){
      $enemy_2 = $b[$index]; 
      if($enemy_1 < $enemy_2){
        $enemies[$enemy_2] = max($enemies[$enemy_2],$enemy_1);
      }else if($enemy_2 < $enemy_1){
        $enemies[$enemy_1] = max($enemies[$enemy_1],$enemy_2);   
      }
   }

Вычисления:

   $prev_start = 1;
   $count = 0; 

   for($i=1;$i<=$n;++$i){
     if($enemies[$i] !== -1){
         $prev_start = max($enemies[$i] + 1,$prev_start);
     }

     $count += ($i - $prev_start + 1);
   }
  • Поскольку мы предварительно обработали детали противника, мы обновляем $prev_start соответственно с того места, где мынеобходимо снова начать подсчет групп.

  • $count += ($i - $prev_start + 1); просто подсчитывает количество групп (подмассивов), которые необходимо учитывать при подсчете.

  • Сложность времени: O(m + n), где m - количество пар, а n - количество собак / животных.

  • Сложность пространства: O(n), где n - количество собак / животных.

Полный код:

<?php

function countSubarrays($n, $a, $b) {
   $enemies = array_combine(range(1,$n),array_fill(0,$n,-1)); // nothing tricky, just generates an array filled with sequential numbers as keys and sets it's value as -1

   foreach($a as $index => $enemy_1){
      $enemy_2 = $b[$index]; 
      if($enemy_1 < $enemy_2){
        $enemies[$enemy_2] = max($enemies[$enemy_2],$enemy_1);
      }else if($enemy_2 < $enemy_1){
        $enemies[$enemy_1] = max($enemies[$enemy_1],$enemy_2);   
      }
   }

   $prev_start = 1;
   $count = 0; 

  for($i=1;$i<=$n;++$i){
     if($enemies[$i] !== -1){
         $prev_start = max($enemies[$i] + 1,$prev_start);
     }

     $count += ($i - $prev_start + 1);
  }

   return $count;
}

Демо: https://3v4l.org/1W26C

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...