You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何生成指定和与固定长度的正整数拆分组合?

问题说明

你要解决的这个数学问题叫固定项数的正整数分拆(也叫「有序k分拆」,k就是你说的组合长度),说白了就是找所有长度为指定值的正整数序列,加起来等于目标和。

现有代码的问题

你给的代码只写了开头的初始化逻辑,既没实现生成所有组合的核心逻辑,也没用到生成器的yield输出结果,等于没完成核心功能。

完善后的代码方案

下面给你两种实现:一种是完全贴合你的需求(只用正整数,不用自定义可选数)的简化版,另一种是保留原函数参数、支持自定义可选数字的版本。

简化版(完全贴合你的需求)

这个版本不用传可选数字集合,直接生成所有符合要求的正整数组合:

function getFixedLengthIntegerPartitions(int $targetSum, int $setLength): \Generator {
    // 边界检查:每个数至少是1,目标和必须不小于组合长度,否则无解
    if ($targetSum < $setLength) {
        return;
    }

    // 递归生成组合的内部函数
    $generate = function(int $remainingSum, int $remainingLength, array $currentCombination) use (&$generate) {
        // 只剩最后一个位置时,直接填入剩余值并输出组合
        if ($remainingLength === 1) {
            $currentCombination[] = $remainingSum;
            yield $currentCombination;
            return;
        }

        // 当前数的取值范围:最小1,最大为剩余总和减去(剩余位置数-1)——保证剩下的位置至少能填1
        $maxCurrent = $remainingSum - ($remainingLength - 1);
        for ($i = 1; $i <= $maxCurrent; $i++) {
            // 递归处理剩余位置,把当前数加入组合
            yield from $generate($remainingSum - $i, $remainingLength - 1, [...$currentCombination, $i]);
        }
    };

    // 启动递归生成逻辑
    yield from $generate($targetSum, $setLength, []);
}

// 使用示例
// 找和为50、长度2的组合
foreach (getFixedLengthIntegerPartitions(50, 2) as $comb) {
    print_r($comb);
}

// 找和为50、长度4的组合
foreach (getFixedLengthIntegerPartitions(50, 4) as $comb) {
    print_r($comb);
}

兼容原参数的版本(支持自定义可选数字)

如果需要保留原函数的$numbers参数,让你可以指定能用哪些数字来组合,就用这个版本:

function getCombinations(array $numbers, int $sum, int $setLength): \Generator {
    // 对可选数字去重、排序,方便后续逻辑处理
    $uniqueNumbers = array_unique($numbers);
    asort($uniqueNumbers);
    $sortedNumbers = array_values($uniqueNumbers);
    $minNum = $sortedNumbers[0] ?? 0;

    // 边界检查:如果最小数字乘组合长度都大于目标和,直接返回空
    if ($minNum * $setLength > $sum) {
        return;
    }

    // 递归生成组合的内部函数,startIndex用于避免重复组合(比如[1,49]和[49,1]只生成一次)
    $generate = function(int $remainingSum, int $remainingLength, array $currentCombination, int $startIndex) use (&$generate, $sortedNumbers, $minNum) {
        // 只剩最后一个位置时,检查剩余值是否在可选数字中,符合则输出组合
        if ($remainingLength === 1) {
            if (in_array($remainingSum, $sortedNumbers)) {
                $currentCombination[] = $remainingSum;
                yield $currentCombination;
            }
            return;
        }

        // 从startIndex开始遍历,避免重复组合;如果需要生成有序组合(比如[1,49]和[49,1]都要),把startIndex改成0即可
        for ($i = $startIndex; $i < count($sortedNumbers); $i++) {
            $num = $sortedNumbers[$i];
            $newRemaining = $remainingSum - $num;
            // 剩余总和必须满足剩下的位置每个都能放最小数字,否则跳过后续更大的数字
            if ($newRemaining >= $minNum * ($remainingLength - 1)) {
                yield from $generate($newRemaining, $remainingLength - 1, [...$currentCombination, $num], $i);
            } else {
                // 数字已排序,后续更大,直接跳出循环节省时间
                break;
            }
        }
    };

    // 启动递归生成逻辑
    yield from $generate($sum, $setLength, [], 0);
}

// 使用示例(用1到49的正整数组合出和为50、长度2的序列)
$positiveIntegers = range(1, 49);
foreach (getCombinations($positiveIntegers, 50, 2) as $comb) {
    print_r($comb);
}
关键说明
  • 用生成器(Generator)的好处是不用一次性把所有组合加载到内存中,目标和较大时不会出现内存溢出问题。
  • 简化版逻辑更直接,完全匹配你的需求;兼容版更灵活,可应对自定义可选数字的场景。

内容的提问来源于stack exchange,提问作者rafark

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 14:39:25