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

实现N选X组合生成函数(迭代/递归方案均可)

实现N选X的组合生成函数

需求描述

给定一个包含N个元素的列表,例如:

const list = [0, 1, 2, ...(N-1)];

需要实现函数findAllCombinations(x, list),生成列表中所有X个元素的组合,对应数学中的组合数(N choose X)。

已知X=2时的迭代写法示例:

const findAllCombinations = (x, list) => {
    for(let i = 0; i < list.length; i++){
      for(let j = i+1; j < list.length; j++){
           // N选2的逻辑
       }
     }
};

但无法将此逻辑扩展到通用的N选X场景,优先需要迭代式实现,也接受递归方案。

错误的递归尝试及问题

以下是存在缺陷的递归实现:

const combine = (x, list) => {
    
    // 注:N = list.length

    if(list.length < x){
        throw new Error('not enough elements to combine.');
    }

    if (x < 1) {
        return [];
    }

    const ret = [];

    for(let v of combine(x-1, list.slice(1))){
        ret.push([list[0], ...v]);
    }

    return ret;
}
    
console.log(
   combine(3, ['a','b','c','d'])
)

问题:该代码仅生成包含列表第一个元素的组合(如[a,b,c]、[a,b,d]、[a,c,d]),漏掉了不包含第一个元素的组合[b,c,d],无法得到(4 choose 3)=4的完整结果。同时边界条件处理错误:当x=0时,正确结果应为[[]](因为N choose 0=1),但当前代码返回空数组。

正确的递归实现

修正边界条件,并补充“不包含当前元素”的递归分支:

const combine = (x, list) => {
    const n = list.length;
    
    // 边界条件:元素不足,抛出错误
    if (n < x) {
        throw new Error('not enough elements to combine.');
    }
    
    // 边界条件:选0个元素,返回包含空数组的列表
    if (x === 0) {
        return [[]];
    }
    
    // 边界条件:选全部元素,返回包含原列表的列表
    if (x === n) {
        return [list.slice()];
    }
    
    const result = [];
    
    // 情况1:包含当前第一个元素,递归处理剩余元素选x-1个
    for (const subset of combine(x - 1, list.slice(1))) {
        result.push([list[0], ...subset]);
    }
    
    // 情况2:不包含当前第一个元素,递归处理剩余元素选x个
    result.push(...combine(x, list.slice(1)));
    
    return result;
};

测试验证:

console.log(combine(0, [1,2,3])); // [[]] → 正确
console.log(combine(1, [1,2,3])); // [[1],[2],[3]] → 正确
console.log(combine(2, [1,2,3])); // [[1,2],[1,3],[2,3]] → 正确
console.log(combine(3, [1,2,3])); // [[1,2,3]] → 正确
console.log(combine(3, ['a','b','c','d'])); // [[a,b,c],[a,b,d],[a,c,d],[b,c,d]] → 正确

迭代式实现(回溯法)

通过回溯的迭代方式生成所有组合,避免递归调用:

const findAllCombinations = (x, list) => {
    const n = list.length;
    if (n < x) throw new Error('not enough elements to combine.');
    if (x === 0) return [[]];
    if (x === n) return [list.slice()];
    
    const result = [];
    const stack = [];
    
    // 初始化栈:每个元素保存当前起始索引、当前组合
    stack.push({ start: 0, current: [] });
    
    while (stack.length > 0) {
        const { start, current } = stack.pop();
        
        // 如果当前组合长度等于x,加入结果
        if (current.length === x) {
            result.push(current);
            continue;
        }
        
        // 从start开始遍历,避免重复组合
        for (let i = start; i < n; i++) {
            // 剪枝:剩余元素数量足够时才继续
            if ((n - i - 1) >= (x - current.length - 1)) {
                stack.push({
                    start: i + 1,
                    current: [...current, list[i]]
                });
            }
        }
    }
    
    return result;
};

测试验证:

console.log(findAllCombinations(2, [0,1,2,3])); 
// 输出:[[0,1],[0,2],[0,3],[1,2],[1,3],[2,3]] → 正确

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 21:25:24