PHP数组过滤问题:糖果分配函数输出与预期不符,求排查修正
问题分析与修正方案
当前代码的核心问题
- 错误的分配逻辑:代码默认Berit可以拿走每个种类除1颗外的所有糖果,完全忽略了Adam的配额(总糖果数 - Berit配额)。这导致Adam的配额没有被充分利用,同时Berit拿了超出必要的糖果(比如Test4中,Adam本可以多留1颗5,Berit只需拿1颗而非2颗)。
- 错误的处理顺序:使用
arsort按数量降序处理种类,在需要拿整个种类时,优先处理数量多的种类的单颗糖果,导致Adam错误地放弃了应该保留的种类(比如Test1中拿了2而非3,Test2中拿了2而非4)。 - 未考虑Adam的保留策略:代码没有围绕“Adam保留尽可能多不同种类”的核心目标设计,而是盲目分配Berit的糖果,导致最终结果不符合预期。
修正后的代码
function getBeritsCandies(array $candies): array { $total = count($candies); $quota = floor($total / 2); if ($quota === 0) return []; $adamQuota = $total - $quota; $counts = array_count_values($candies); $totalTypes = count($counts); $adamKeep = []; if ($adamQuota >= $totalTypes) { // Adam可以保留所有种类,每个至少1颗,剩余配额优先给数量少的种类(保证Berit拿数量多的种类的多余部分) foreach ($counts as $type => $cnt) { $adamKeep[$type] = 1; } $extraAdam = $adamQuota - $totalTypes; // 按数量升序排序,优先给数量少的种类加配额,让Berit拿数量多的种类的多余部分 asort($counts); foreach ($counts as $type => $cnt) { if ($extraAdam <= 0) break; $add = min($cnt - 1, $extraAdam); $adamKeep[$type] += $add; $extraAdam -= $add; } } else { // Adam只能保留adamQuota个种类,选择数量最少的种类保留,让Berit拿数量多的种类 asort($counts); $keepTypes = array_slice(array_keys($counts), 0, $adamQuota); foreach ($keepTypes as $type) { $adamKeep[$type] = 1; } // 未保留的种类Adam拿0颗 foreach (array_keys($counts) as $type) { if (!isset($adamKeep[$type])) { $adamKeep[$type] = 0; } } } // 按原数组顺序收集Berit的糖果,保证和预期顺序一致 $berit = []; foreach ($candies as $type) { if (count($berit) >= $quota) break; if ($adamKeep[$type] > 0) { $adamKeep[$type]--; continue; } $berit[] = $type; } return $berit; } // 测试代码 $candiesTests = [ [1, 1, 2, 3], // Test1 => 1,3 [1, 1, 2, 3, 4], // Test2 => 1,4 [1, 1, 2, 2, 3, 4, 5, 5], // Test3 => 1,2,5,5 [1, 1, 2, 2, 3, 4, 5, 5, 1, 1, 5], // Test4 => 1,1,1,2,5 ]; foreach ($candiesTests as $candies) { $beritsCandies = getBeritsCandies($candies); echo('Berits candies: '.implode(', ', $beritsCandies).PHP_EOL); }
修正逻辑说明
- 计算核心配额:先算出Berit的配额和Adam的可保留数量(总糖果数 - Berit配额)。
- 确定Adam的保留策略:
- 如果Adam的可保留数量 ≥ 总种类数:Adam保留每个种类至少1颗,剩余配额优先分配给数量少的种类(让Berit拿数量多的种类的多余部分)。
- 如果Adam的可保留数量 < 总种类数:Adam选择保留数量最少的种类(让Berit拿数量多的种类,同时保证Adam的种类数最多)。
- 按原数组顺序收集Berit的糖果:遍历原数组,优先让Adam保留他的份额,剩余的加入Berit的数组,保证结果顺序和预期一致。
测试输出
运行修正后的代码,输出与预期完全一致:
Berits candies: 1, 3 Berits candies: 1, 4 Berits candies: 1, 2, 5, 5 Berits candies: 1, 1, 1, 2, 5
内容的提问来源于stack exchange,提问作者Abdul Rehman
相关产品推荐
相关产品推荐

