PHP-查找给定一些约束的组数

PHP-查找给定一些约束的组数,php,logic,Php,Logic,假设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) 结果表明:共可

假设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组

案例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);
}
函数countsubstring($n,$a,$b){
$tokenArr=array();
$x=1;
而($x$valuea){
if(在数组中($valuea,$intersects)){
未结算($outArr[$keya]);
}
}
返回计数(超出);
}

到目前为止,我的代码在以下情况下工作:#1但在#2上失败。

对我来说,交叉逻辑似乎不正确,因为我们必须检查由
[a,b]
形成的关系,例如,
[1,2]
是否存在于
$outArr
中。当前对
计数(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);
演示:

在上述代码中,我们:

  • 在foreach中的
    $index
    帮助下,循环遍历
    $a
    的所有元素,并与
    $b
    同时循环

  • 检查对于
    $outArr
    中的当前组,组中是否同时存在
    $a[$index]
    (a.k.a
    $val1
    )和
    $b[$index]
    (a.k.a
    $val2

  • 如果两者都存在于当前组中,我们将它们置于intersect下,因为它们是敌人。你剩下的逻辑是正确的


高效解决方案:

  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.
$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);
   }
<?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;
}
  • 我们必须利用这条线:
一个群体被定义为一个区间(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.
$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);
   }
<?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;
}
  • 因此,我们的下一个出发点动物/狗是
    4

  • 对于每一个敌人/动物,我们在左侧保留最近的敌人(如果存在)。如果存在,我们将更新下一个动物,以查找如上所述的组。在下面的代码中,
    $prev_start
    是用于维护下一个要查看的动物的变量

  • 为了得到每只动物左侧最近的敌人,我们对敌人细节进行了如下预处理:

预处理:

  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.
$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);
   }
<?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;
}

演示:

很好的尝试。intersect逻辑对我来说似乎不正确,因为我们必须检查由
[a,b]
形成的关系,例如,
[1,2]
是否存在于
$outArr
中。当前对
计数(array_intersect($outArr[$k],$a))>1的检查与此无关。而是检查
$a
中的任何元素是否存在于
$outArr[$k]
中。这不是关于数组相交,而是关于检查的方式。无论如何,我已经添加了一个答案。我认为我们可以进一步优化它。完成后我会通知你。@Carl我正在尝试优化的一个,你的问题是
m=一些x对敌人
,所以
$a
拥有
(1,2,3,4,5)
$b
拥有
(1,3,5)
没有意义。它们在每个索引处形成一对。因此,毫无疑问,
count($a)
不等于
count($b)
。@Carl是的,请更新您的问题,最好按原样共享原始文档。@Carl所以这是黑客银行的挑战。是的,
m
对于
a
b
都将保持不变,但从约束条件来看,暴力不会被接受。@Carl看看这个解决方案是否通过。一旦确认它是正确的,我会加上解释。@Carl好极了。补充说明:)