说我有一个数组[10000,5000,1000,1000],我想找到与给定数字最接近的数字总和。抱歉,我们的解释不正确,但是这里有一个例子:
说我有一个数组[10000,5000,1000,1000]我想找到最接近的数字,例如6000。
然后该方法应返回5000和1000
另一个例子:我们想要最接近14000,那么他应该返回10000和5000
我尝试使用下面的代码,但是这里工作正常,但是如果 $ desiredSum 和 $ numbers数组大。在php执行超时之前,它的运行是如此缓慢
$numbers = array(
10000,5000,1000,1000
);
$desiredSum = 6000;
$minDist = null;
$minDist_I = null;
// Iterate on every possible combination
$maxI = pow(2,sizeof($numbers));
for($i=0;$i<$maxI;$i++) {
if(!(($i+1) % 1000)) echo ".";
// Figure out which numbers to select in this
$sum = 0;
for($j=0;$j<sizeof($numbers);$j++) {
if($i & (1 << $j)) {
$sum += $numbers[$j];
}
}
$diff = abs($sum - $desiredSum);
if($minDist_I === null || $diff < $minDist) {
$minDist_I = $i;
$minDist = $diff;
}
if($diff == 0) break;
}
$chosen = array();
for($j=0;$j<sizeof($numbers);$j++) {
if($minDist_I & (1 << $j)) $chosen[] = $numbers[$j];
}
echo "\nThese numbers sum to " . array_sum($chosen) . " (closest to $desiredSum): ";
echo implode(", ", $chosen);
echo "\n";
有人可以帮助我吗?
答案 0 :(得分:0)
<?php
function coinChange($numbers,$desiredSum){
sort($numbers);
$set = [];
$set[0] = [];
for($i = $numbers[0];$i <= $desiredSum;++$i){
foreach($numbers as $index => $current_number){
if($i >= $current_number && isset($set[$i - $current_number])){
if(isset($set[$i - $current_number][$index])) continue;
$set[$i] = $set[$i - $current_number];
$set[$i][$index] = true;
break;
}
}
}
if(count($set) === 0){
return [0,[]];
}
if(isset($set[$desiredSum])){
return [
$desiredSum,
formatResult($numbers,array_keys($set[$desiredSum]))
];
}else{
$keys = array_keys($set);
$nearestSum = end($keys);
$sum = 0;
$rev_numbers = array_reverse($numbers);
$result = [];
foreach($rev_numbers as $number){
$sum += $number;
$result[] = $number;
if($sum > $nearestSum && abs($nearestSum - $desiredSum) > abs($sum - $desiredSum)){
$nearestSum = $sum;
break;
}else if($sum > $nearestSum && abs($nearestSum - $desiredSum) < abs($sum - $desiredSum)){
$result = formatResult($numbers,array_keys($set[$nearestSum]));
break;
}
}
return [
$nearestSum,
$result
];
}
}
function formatResult($numbers,$keys){
$result = [];
foreach($keys as $key) $result[] = $numbers[$key];
return $result;
}
print_r(coinChange([10000,5000,1000,1000],14000));
print_r(coinChange([10000,5000,1000,1000],13000));
print_r(coinChange([100000,100000,100000,100000,100000,100000,50000,50000,50000,50000,10000,10000,500,500,500,1000,1000],250000));
print_r(coinChange([100000,100000,100000,100000,100000,100000,50000,50000,50000,50000,10000,10000,500,500,500,1000,1000],179999));
算法:
这类似于coin change问题。
我们首先对数字进行排序。
$i
,我们就只能使$i - $current_number
(这是总和)成为可能。如果我们有前一个,则将$current_number
加到集合中以求和$i
。两种情况:
$set
中已经有最接近的总和,这将是最后一个条目。我们将它们保留在变量中。结果格式:
让我们看下面的示例输出:
Array
(
[0] => 15000
[1] => Array
(
[0] => 10000
[1] => 5000
)
)
这只是意味着第一个索引是可能的最接近的总和,第二个索引处的数组是从$numbers
获取该总和的所有元素。