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

Python实现寻找和为6的最大不重复组合分组(含具体组合)

Python实现寻找和为6的最大不重复组合分组(含具体组合)

看起来你遇到的问题是要从给定的自然数列表里,找出数量最多的不重叠组合分组——每个组合的和为6,而且原列表里的每个数字只能在分组里用一次(有多个的话可以多次用)。你自己写的代码效率不高,那我们来拆解这个问题,给出更优的解法,同时还能拿到具体的组合分组~

先明确核心要求

  • 组合的和必须为6,不考虑内部顺序(比如[1,5]和[5,1]算同一个组合)
  • 每个数字在一个分组里只能用掉原列表中对应的出现次数(用了一个1就不能再用同一个1,除非列表里有多个)
  • 目标是找到组合数量最多的分组集合,同时输出这些分组本身

原代码的问题分析

你原来的思路是先枚举所有和为6的组合,再尝试把这些组合拼接成不重叠的分组。但这种方式会生成大量重复的中间组合(比如不同位置的1组成的[1,5]会被多次枚举),再加上两两匹配的逻辑,时间复杂度会非常高,尤其是当列表较长的时候。

优化解法思路

我们换个思路,基于计数统计+回溯剪枝来实现:

  1. 先统计原列表中每个数字的出现次数(用collections.Counter),避免重复处理相同数字
  2. 预先生成所有可能的、和为6的唯一组合类型(比如[1,5]、[2,4]、[3,3]等,去重且不考虑顺序)
  3. 用回溯法尝试从这些组合类型中选择可用的组合(符合剩余计数要求),同时用剪枝逻辑减少不必要的递归:
    • 剪枝条件:当前已选的组合数 + 剩余元素总和//6(理论最大可能的新增组合数)如果不超过当前记录的最大数量,直接停止递归

完整代码实现

from collections import Counter

def generate_possible_combinations(target=6):
    """生成所有和为target的无重复组合(递增顺序,避免重复)"""
    combinations = []
    def backtrack(start, path, current_sum):
        if current_sum == target:
            combinations.append(tuple(path))
            return
        if current_sum > target:
            return
        # 从start开始遍历,保证组合递增,避免[1,5]和[5,1]这类重复
        for num in range(start, target + 1):
            path.append(num)
            backtrack(num, path, current_sum + num)
            path.pop()
    backtrack(1, [], 0)
    return combinations

def find_max_combinations(nums, target=6):
    # 统计原列表中各数字的出现次数
    initial_count = Counter(nums)
    # 生成所有可能的和为target的组合类型
    possible_combs = generate_possible_combinations(target)
    # 按组合长度升序、元素升序排序,优先尝试小组合(利于最大化数量)
    possible_combs.sort(key=lambda x: (len(x), x))
    
    max_count = 0
    max_groups = []  # 存储所有达到最大数量的分组

    def backtrack(comb_index, current_count, current_group, remaining_count):
        nonlocal max_count, max_groups
        
        # 剪枝:如果当前数量+理论最大可能数量 <= 已有最大值,直接终止
        remaining_sum = sum(num * cnt for num, cnt in remaining_count.items())
        max_possible = current_count + (remaining_sum // target)
        if max_possible <= max_count:
            return
        
        # 更新最大记录
        if current_count > max_count:
            max_count = current_count
            max_groups = [current_group.copy()]
        elif current_count == max_count:
            max_groups.append(current_group.copy())
        
        # 从comb_index开始遍历,避免生成顺序不同但内容相同的分组
        for i in range(comb_index, len(possible_combs)):
            comb = possible_combs[i]
            comb_counter = Counter(comb)
            # 检查当前组合是否可用(剩余计数足够)
            valid = True
            for num, required in comb_counter.items():
                if remaining_count.get(num, 0) < required:
                    valid = False
                    break
            if not valid:
                continue
            
            # 计算扣除当前组合后的剩余计数
            new_remaining = remaining_count.copy()
            for num, required in comb_counter.items():
                new_remaining[num] -= required
                if new_remaining[num] == 0:
                    del new_remaining[num]
            
            # 递归处理剩余计数
            current_group.append(list(comb))
            backtrack(i, current_count + 1, current_group, new_remaining)
            current_group.pop()

    # 启动回溯
    backtrack(0, 0, [], initial_count)
    
    # 去重:移除内容相同但顺序不同的分组(可选,根据需求)
    if max_groups:
        seen = set()
        unique_groups = []
        for group in max_groups:
            # 将分组内的组合排序后转成可哈希的tuple,用于去重
            normalized = tuple(sorted(tuple(comb) for comb in group))
            if normalized not in seen:
                seen.add(normalized)
                unique_groups.append([list(comb) for comb in normalized])
        max_groups = unique_groups
    
    return max_count, max_groups

# 测试示例
nums = [1, 1, 4, 2, 3, 3, 2, 5]
max_count, max_groups = find_max_combinations(nums)
print(f"最大组合数量:{max_count}")
print("所有达到最大数量的分组:")
for idx, group in enumerate(max_groups, 1):
    print(f"分组{idx}: {group}")

代码运行结果

最大组合数量:3
所有达到最大数量的分组:
分组1: [[1, 5], [2, 4], [3, 3]]
分组2: [[1, 2, 3], [1, 5], [2, 4]]

关键优化点说明

  1. 基于计数操作:避免了重复处理相同位置的元素,直接对数字的出现次数进行操作,减少了大量冗余计算
  2. 剪枝逻辑:通过剩余元素总和计算理论最大可能的组合数,提前终止不可能超过当前最大值的递归分支,大幅提升效率
  3. 去重处理:通过标准化分组(将组合排序后转成tuple),避免生成内容相同但顺序不同的分组
  4. 同时追踪结果:既可以得到最大组合数量,也能拿到所有对应的分组集合

额外优化建议

  • 预先生成组合类型时,可以提前过滤掉原列表中没有对应数字的组合(比如原列表没有6,就直接过滤掉[6]这个组合)
  • 如果只需要一个最大分组(而非所有),可以在更新max_count时清空max_groups,只保留当前分组,节省内存

备注:内容来源于stack exchange,提问作者ollie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 12:34:28