本小节,介绍下从一维数组中,采取排列组合的思想,依次遍历每个元素查找出符合业务需求的数据。举个例子:一维数组 [1, 2, 3, 4, 5] 中,查找出任意3个元素是10的倍数,并且取出剩下的两位。接下来,我们从最基础的循环中来慢慢优化我们的算法。

摘自百度百科:排列组合是组合学最基本的概念。所谓排列,就是指从给定个数的元素中取出指定个数的元素进行排序。组合则是指从给定个数的元素中仅仅取出指定个数的元素,不考虑排序。
    先来个循环吧
public function circulation()    
{
// 初始化计数
$count = 0;
$arr=[1, 2, 3, 4, 5];
for( $a=0; $a<5; ++$a ){
$i=$arr[$a];
for( $b=0; $b<5; ++$b ){
$j=$arr[$b];
for( $c=0; $c<5; ++$c ){
++$count; // 计量值++
$k=$arr[$c];
// 符合条件(包含重复)
if ( ($i+$j+$k)%10 ==0 ) {
echo $i.$j.$k." ";
if ( $count%6==0 ) {
echo "<br>";
}
}
}
}
}
// 总循环次数
echo $count; }

结果如下:

虽然元素相加和为10的倍数,但是有两个问题:

  • 循环重复了,比如145 和 154 应该是同一个,不应该出现两次
  • 元素重复了,424 这里的 4 出现了两次
    开始优化

目测下,目标数据应该是:123 124 125 134 135 145 234 235 245 345。这十个数字,其中 145 和 235 符合业务的需求。

    优化思路

从这些目标数据不难发现,第一位数是从 1 开始递增的,第二位是从 2 开始递增的,第三位是从 3 开始递增的。是不是可以这样理解:后面一位的下标是在前面一位的下一位开始的。

    代码实现
public function circulation()
{
// 初始化计数
$count = 0;
$arr=[1, 2, 3, 4, 5];
for( $a=0; $a<5; ++$a ){
$i=$arr[$a];
for( $b=$a+1; $b<5; ++$b ){
$j=$arr[$b];
for( $c=$b+1; $c<5; ++$c ){
++$count;
$k=$arr[$c];
// 符合条件(不包含重复)
if ( ($i+$j+$k)%10 ==0 ) {
// 计算剩余的两位
$arr1 = [$i,$j,$k];
$diff[] = array_diff($arr, $arr1);
echo $i,$j,$k."<br>";
}
}
}
}
// 总循环次数
echo $count;
// 剩余两位
print_r($diff);
}

结果如下:

循环次数大大缩减到 10 次,而且结果也是我们预期的。然后我们利用 array_diff 来获取剩下的两位。到此为止,既定目标达到了,还有没有更进一步的优化空间呢?

    看下面代码,我们一起思考

这里只贴出核心代码:

for( $a=0; $a<3; ++$a ){
$i=$arr[$a];
for( $b=$a+1; $b<4; ++$b ){
$j=$arr[$b];
for( $c=$b+1; $c<5; ++$c ){
++$count;
$k=$arr[$c];
if ( ($i+$j+$k)%10 ==0 ) {
// 计算剩余的两位
$arr1 = [$i,$j,$k];
$diff[] = array_diff($arr, $arr1);
echo $i,$j,$k."<br>";
}
}
}
}

第一步,优化的方向是数组下标的起始值,这里我们发现每个数组的临终值也是有规律的。好了,本篇优化循环就到这里了,如果大家有更好的优化思路或文中有不当之处,希望在评论区提出。谢谢!

     无论何时何地,云聚云散皆是美!只是美的形态不一样而已~