我的任务是使用8个区块中的数据创建所有可能性的列表。
8个街区有以下几种可能性:
*Block 1: 12 possibilities
*Block 2: 8 possibilities
*Block 3: 8 possibilities
*Block 4: 11 possibilities
*Block 5: 16 possibilities
*Block 6: 11 possibilities
*Block 7: 5 possibilities
*Block 8: 5 possibilities
这可能有37,171,200种可能性。
我只是尝试并限制只显示返回的值,使用正确的字符串长度,如下所示:
foreach($block1 AS $b1){
foreach($block2 AS $b2){
foreach($block3 AS $b3){
foreach($block4 AS $b4){
foreach($block5 AS $b5){
foreach($block6 AS $b6){
foreach($block7 AS $b7){
foreach($block8 AS $b8){
if (strlen($b1.$b2.$b3.$b4.$b5.$b6.$b7.$b8) == 16)
{
echo $b1.$b2.$b3.$b4.$b5.$b6.$b7.$b8.'<br/>';
}
}
}
}
}
}
}
}
}
然而,执行时间太长而无法计算。我想知道是否有人知道更简单的方法吗?
答案 0 :(得分:3)
您可以尝试将预先计算的部分存储在前面每个lelel中已知的连接字符串中,以便以后重用,避免连接最内层循环中的所有内容
foreach($block7 AS $b7){
$precomputed7 = $precomputed6.$b7
foreach($block8 AS $b8){
$precomputed8 = $precomputed7.$b8
if (strlen($precomputed8) == 16) {
echo $precomputed8.'<br/>';
}
}
}
类似于先例水平。然后你可以尝试在更高的循环级别之一测试已经更长为16个字符的字符串。您可以快捷方式,避免尝试其他可能性。但要注意计算字符串的长度会花费很多性能,也许后者的改进根本不值得,具体取决于输入数据。
另一个想法是预先计算每个块的长度,然后递归长度数组,计算总和应该比连接和计算字符串长度更快。对于匹配长度为16的索引Vector,您可以轻松输出完整的连接字符串。
答案 1 :(得分:3)
您可以通过缓存字符串前缀并记住它们的长度来改进算法。然后你不必为每个组合做到这一点。
$len = 16:
// array for remaining characters per level
$r = array($len);
// array of level parts
$p = array();
foreach ($block1 AS &$b1) {
// skip if already too long
if (($r[0] - strlen($b1)) <= 0) continue;
$r[1] = $r[0] - strlen($b1);
foreach ($block2 AS &$b2) {
if (($r[1] - strlen($b2)) <= 0) continue;
$r[2] = $r[1] - strlen($b2);
foreach ($block3 AS $b3) {
// …
foreach ($block8 AS &$b8) {
$r[8] = $r[7] - strlen($b8);
if ($r[8] == 0) {
echo implode('', $p).'<br/>';
}
}
}
}
}
此外,使用foreach
中的引用将在内部使用数组副本停止PHP。
答案 2 :(得分:2)
由于您的长度要求为16,并且假设每个(i)八个块中每个(b)的可能性具有长度x_i_b,您可以通过某些情况得到一些减少。
例如,假设我们有长度要求16,但只有4个块,可能有长度指示
第1块:[2,3,4] 第2块:[5,6,7] 第3块:[8,9,10] 第4块:[9,10,11]
然后所有可能性都是不可能的,因为块4的长度都太大而不允许构成16的其余部分的块1-3的任何组合。
现在,如果你的长度真的是16,则意味着你的(可能的)长度范围从1到9,假设没有0长度。
我可以看到两种方法来解决这个问题:
甚至可能将它们结合起来。对于贪婪的方法,选择所有区块中最大的可能性,然后是下一个最大的区域,直到你越过16的门槛。如果你得到了所有的区块,那么你可以发射那个区块。
无论你是否达到了门槛,你都可以迭代这些可能性。
动态appraoch意味着您应该存储已经计算过的一些结果。就像从一些块中选择一个长度为7的块,你不需要在将来重新计算它,但你可以遍历其余的块,看看你是否能找到一个组合来给你9。 / p>
编辑:这有点像背包问题,但每个实例每个块有1个选择的附加限制。无论如何,就其他优化而言,绝对只需将块处理成长度数组,并在每个迭代级别保持运行总和。因此,每次循环每次迭代只需要1次求和,而不是每次迭代得到8次求和。如果需要发出选择,也只有str concat。
如果您不想要一般解决方案(如果不这样做可能会更容易),那么您可以通过排除最大的太小的长度组合(以及所有小于此的选择)来手动编写很多问题实例特定的加速代码,排除最小的太大的长度组合(以及所有选择的更大)。
答案 3 :(得分:1)
如果您可以将其表达为嵌套数组,请尝试使用RecursiveIteratorIterator,http://php.net/manual/en/class.recursiveiteratoriterator.php