这个问题也比较常见,网上方法也很多。 这里也是用数组的方法来完成。用到了集合、子集的思想。注释中详细说明了。
从m个数中选出n个数来 ( 0 < n <= m), 要求n个数之间不能有重复,其和等于一个定值k, 求一段程序,罗列所有的可能。
如从 [11, 18, 12, 1, -2, 20, 8, 10, 7, 6] 中取出之和为18的集合,如[11,7][18]等。
<?php
header('Content-type: text/html; charset=utf-8');
/**
* 从m个数中选出n个数来 ( 0 < n <= m), 要求n个数之间不能有重复,其和等于一个定值k, 求一段程序,罗列所有的可能。
* @param int $need 定值
* @param array $arr 选取的数组集合
* @return array 符合的子集合
*/
function sel_set($need, $arr) {
//子集数2的数组元素数次方
$arr_count = count($arr);
$set_count = pow(2, $arr_count);
/**
* 此方法原理: 对于集合{a, b, c}
* 针对其中的元素都有2种状态1在子集中0不在
* 0=>0 0 0 空集不需要考虑
* 1=>0 0 1 => c
* 2=>0 1 0 => b
* 3=>0 1 1 => b c
* 4=>1 0 0 => a
* 5=>1 0 1 => a c
* 6=>1 1 0 => a b
* 7=>1 1 1 => a b c
* 也就是将每个子集对应的编号转化为二进制 再去数组取对应元素
*/
//set_arr用来存放符合需求的子集
$set_arr = array();
//set_count个子集,所以循环set_count次
for( $i = 1; $i < $set_count; $i++ ) {
//tmp用来存放每次子集
$tmp = array();
//将子集对应编号转化二进制
$dec = decbin($i);
//数组集合有arr_count个元素,所以将二进制左补0为对应位,以便取数组元素
$dec = str_pad($dec, $arr_count, 0, STR_PAD_LEFT);
//对该二进制数循环 判断是否为1
for( $j = 0; $j < $arr_count; $j++ ) {
//如果当前位为1, 则将数组对应元素放入子集数组
if( 1 == $dec[$j] ) {
array_push($tmp, $arr[$j]);
}
}
//判断当前子集之和是否等于设定的定值,符合则存入set_arr
if( $need == array_sum($tmp) ) {
array_push($set_arr, json_encode($tmp));
}
}
//返回符合要求的集合
return $set_arr;
}
//要进行选取的数组,及定值
$need = 18;
$arr = array(11, 18, 12, 1, -2, 20, 8, 10, 7, 6);
sel_set($need, $arr);