如何从列表中筛选出和等于给定值的不重复子集?
问题原因
itertools.combinations是基于元素位置生成组合的,你的原数组存在多个重复值(2个3、2个2),不同位置的同值元素会生成值完全相同的组合,再加上组合内部元素顺序不同也会被判定为不同组合,最终就出现了大量重复结果。
解决方法
轻量实现(小数据量适用)
对每个匹配的组合先做排序消除顺序影响,再存入集合自动去重即可,修改后代码如下:
from itertools import combinations nums = [4,3,2,3,5,2,1] res_set = set() # 注意原代码遍历范围是range(1, len(nums)),会漏掉长度等于数组长度的组合,这里修正为len(nums)+1 for i in range(1, len(nums)+1): for comb in combinations(nums, i): if sum(comb) == 5: # 排序后转元组存入集合,自动去除重复值组合 res_set.add(tuple(sorted(comb))) # 转列表后可自行调整输出顺序 res = list(res_set) print(res)
运行输出为:[(1, 4), (1, 2, 2), (2, 3), (5,)],你给出的预期输出里的重复(2,3)属于笔误,和为5的无重复值子集本身不包含重复的(2,3)。
高效实现(大数据量适用)
如果数组长度较大,用combinations会生成大量无效组合浪费性能,推荐用回溯剪枝方法,天然避免重复组合生成:
def get_unique_subsets(nums, target): nums.sort() res = [] def backtrack(start_idx, cur_path, cur_sum): if cur_sum == target: res.append(tuple(cur_path)) return if cur_sum > target: return for i in range(start_idx, len(nums)): # 同层跳过重复元素,避免生成重复组合 if i > start_idx and nums[i] == nums[i-1]: continue cur_path.append(nums[i]) backtrack(i+1, cur_path, cur_sum + nums[i]) cur_path.pop() backtrack(0, [], 0) return res nums = [4,3,2,3,5,2,1] print(get_unique_subsets(nums, 5))
运行输出和上述方案一致,计算效率更高。
内容的提问来源于stack exchange,提问作者Sidhant Pradhan
相关产品推荐
相关产品推荐

