PHP-查找给定一些约束的组数
假设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: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 = 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好极了。补充说明:)