
本文介绍一种高效算法,用于计算在每组必须恰好包含指定数量(如2个)不同产品的情况下,从各产品库存数组中能生成的最大组合数。核心思路是贪心策略:每次优先消耗库存最多的几个产品,直到无法再凑齐所需产品种类为止。
本文介绍一种高效算法,用于计算在每组必须恰好包含指定数量(如2个)不同产品的情况下,从各产品库存数组中能生成的最大组合数。核心思路是贪心策略:每次优先消耗库存最多的几个产品,直到无法再凑齐所需产品种类为止。
在电商、库存调度或资源分配场景中,常需解决这类问题:给定若干产品的可用数量(例如 [4, 4, 2] 表示产品A有4件、B有4件、C有2件),要求每次组合必须且仅能选取 k 种不同产品各1件(如 k = 2,即每组含2个不同产品),问最多能组成多少组?这本质上是求最大可行配对轮次数,而非简单求和或取最小值。
✅ 正确解法:贪心 + 降序维护
关键洞察在于:为最大化总组数,每轮应始终从当前库存最多的 k 个产品中各取1件。这样可延缓“断供”(某产品归零)的发生,避免过早浪费高库存产品。
以下是清晰、健壮的 PHP 实现:
<?php
$required_products = 2; // 每组必需的不同产品种类数
$group_iten = [4, 4, 2]; // 各产品初始库存
// 降序排列,确保每次取的是当前最多的 k 个
rsort($group_iten);
$count = 0;
// 循环条件:至少前 k 个产品库存均 > 0(才能凑出一组)
while (count($group_iten) >= $required_products
&& $group_iten[$required_products - 1] > 0) {
// 从库存最多的前 k 个产品中各减 1
for ($j = 0; $j < $required_products; $j++) {
$group_iten[$j]--;
}
// 重新降序排序,为下一轮准备
rsort($group_iten);
$count++;
}
echo "最大可能组合数: " . $count; // 输出:5
?>? 执行过程可视化(以 [4,4,2] 为例):
| 轮次 | 排序后数组 | 操作(减前2位) | 新数组(重排后) |
|---|---|---|---|
| 初始 | [4,4,2] |
→ [3,3,2]
|
[3,3,2] |
| 1 | [3,3,2] |
→ [2,2,2]
|
[2,2,2] |
| 2 | [2,2,2] |
→ [1,1,2]
|
[2,1,1] |
| 3 | [2,1,1] |
→ [1,0,1]
|
[1,1,0] |
| 4 | [1,1,0] |
→ [0,0,0]
|
[0,0,0] |
| 5 | [0,0,0] |
❌ 第2小值为0 → 终止 | — |
✅ 共执行 5 轮,结果正确。
⚠️ 注意事项与优化建议
-
边界安全:务必检查
count($group_iten) >= $required_products,防止数组越界; -
性能考虑:若数据量极大(如千级产品),频繁
rsort()可能成为瓶颈;可改用堆(如 SplMinHeap/SplMaxHeap)维护前k大值,将单轮复杂度从 O(n log n) 降至 O(log n); -
扩展性:该逻辑天然支持任意
k ≥ 1,只需调整$required_products值即可适配“三件套”“四件礼盒”等场景; -
错误规避:原始代码中
unset($group_iten[$i])在循环中动态删元素易引发索引错乱,新方案通过逻辑判断替代删除操作,更安全可靠。
✅ 总结
该问题不是求最小值(min([4,4,2]) = 2 错误)、也不是简单求和除以 k(10/2 = 5 碰巧正确但不普适),而是典型的受限资源贪心分配问题。坚持“每轮消耗当前最充裕的 k 种资源”,辅以动态重排序,即可稳定获得理论最大值。掌握此模式,可快速迁移解决类似调度、配对、抽样类工程问题。

















