
本文详解如何用递归算法生成所有长度为 n、元素均为正整数且和为 target 的组合,支持任意和与长度,适用于分拆、枚举、约束求解等场景。
本文详解如何用递归算法生成所有长度为 n、元素均为正整数且和为 target 的组合,适用于分拆、枚举、约束求解等场景。
在组合数学中,将一个正整数 target 拆分为 n 个正整数之和(允许重复、顺序敏感、不限定最小/最大值)的问题,本质上是求 有界整数划分的有序版本,也称为「带长度约束的组合式整数拆分」(Ordered Integer Compositions of fixed length)。它不同于经典整数划分(partition),因顺序重要(如 [1,49] ≠ [49,1]),且每个部分必须 ≥ 1。
以下是一个健壮、可读性强的 PHP 实现,采用递归回溯思想,确保生成所有满足条件的有序组合(即 compositions),并默认以非降序或自然递增方式隐式遍历(通过控制循环上界避免无效分支):
/**
* 获取所有长度为 $n、元素为正整数、和为 $sum 的有序组合(compositions)
* @param int $sum 目标总和(≥ 1)
* @param int $n 组合长度(≥ 1)
* @return array<int>
*/
function getCombinations(int $sum, int $n): array
{
// 边界校验
if ($n <p>✅ <strong>使用示例:</strong></p>
<pre class="brush:php;toolbar:false;">// 50 拆为 2 个正整数之和(有序)
$combos2 = getCombinations(50, 2);
print_r(array_slice($combos2, 0, 5));
// 输出:[[1,49], [2,48], [3,47], [4,46], [5,45]]
// 50 拆为 4 个正整数之和(前 5 个)
$combos4 = getCombinations(50, 4);
print_r(array_slice($combos4, 0, 5));
// 输出:[[1,1,1,47], [1,1,2,46], [1,1,3,45], [1,1,4,44], [1,1,5,43]]
⚠️ 关键注意事项:
- 本实现默认生成正整数解(每个元素 ≥ 1),符合常见业务需求(如资源分配、名额拆分);若需包含 0,请将循环起始改为
0并调整边界条件($first → <code>$first ),但此时需额外处理空位逻辑。 - 时间复杂度为指数级(O(S^{n−1})),对较大
sum或n(如 sum > 100, n > 6)慎用;生产环境建议配合剪枝、迭代替代递归或使用生成器(yield)流式输出以节省内存。 - 若需去重无序组合(即视为集合而非序列),应在结果层对每组排序后去重(如用
array_unique(array_map('serialize', $results)));但注意:题目示例明确体现顺序性([1,1,1,47]等),故默认保留有序性。
? 进阶提示:
如需提升性能或支持超大输入,可改用动态规划预计算组合数,或借助迭代 DFS + 栈模拟递归;亦可结合 Generator 返回懒加载序列:
function getCombinationsLazy(int $sum, int $n): \Generator
{
if ($n === 1) {
yield [$sum];
return;
}
for ($first = 1; $first <p>掌握该模式,即可灵活应对各类“固定和+固定长度”的枚举任务——无论是测试用例生成、密码空间探索,还是运筹优化中的初始解构造。</p>










