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

使用for循环时如何高效检查重复值?求18长度唯一排列优化方案

高效生成带重复元素的唯一排列(长度18)

我需要获取以下列表的所有唯一排列,要生成长度为18的排列。直接用itertools.permutations再去重会导致电脑崩溃,我试过添加前检查唯一性,但生成6或7长度的排列都要40秒,完全没法处理18长度的情况。有没有更高效的实现方式?

原代码:

pos = ['QB', 'QB', 'QB',
       'RB', 'RB', 'RB', 'RB', 'RB', 'RB', 'RB', 'RB', 'RB', 'RB', 'RB',
       'WR', 'WR', 'WR', 'WR', 'WR', 'WR', 'WR', 'WR', 'WR', 'WR', 'WR',
       'TE', 'TE', 'TE', 'TE', 'TE']

combos = set()

for combo in itertools.permutations(pos, 18):
    if combo not in combos:
        combos.add(combo)

解决方案:避免生成重复排列,直接构造唯一结果

你的核心问题是itertools.permutations会生成大量重复项,事后去重的时间和空间成本完全不可控。正确思路是在生成过程中就跳过重复排列,或者基于元素计数直接构造唯一排列。

方法1:回溯法生成唯一排列

通过跟踪每个元素的剩余可用数量,递归构造排列,从根源上避免重复:

from collections import Counter

pos = ['QB', 'QB', 'QB',
       'RB', 'RB', 'RB', 'RB', 'RB', 'RB', 'RB', 'RB', 'RB', 'RB', 'RB',
       'WR', 'WR', 'WR', 'WR', 'WR', 'WR', 'WR', 'WR', 'WR', 'WR', 'WR',
       'TE', 'TE', 'TE', 'TE', 'TE']

def unique_permutations(elements, target_length):
    elem_counts = Counter(elements)
    elem_keys = list(elem_counts.keys())
    result = []

    def backtrack(current_list):
        if len(current_list) == target_length:
            result.append(tuple(current_list))
            return
        for key in elem_keys:
            if elem_counts[key] > 0:
                # 选择当前元素
                elem_counts[key] -= 1
                current_list.append(key)
                backtrack(current_list)
                # 回溯
                current_list.pop()
                elem_counts[key] += 1

    backtrack([])
    return result

# 生成目标长度的唯一排列
combos = unique_permutations(pos, 18)

方法2:基于位置组合构造排列

如果元素分类明确,可以先确定每种元素的选取数量,再通过组合算法分配位置,避免冗余计算:

import itertools

pos_limits = {'QB': 3, 'RB': 11, 'WR': 11, 'TE': 5}
target_length = 18

def generate_unique_permutations():
    result = []
    # 遍历所有合法的元素数量组合(q+r+w+t=18,且不超过各自上限)
    for q in range(0, min(pos_limits['QB'], target_length) + 1):
        remaining = target_length - q
        for r in range(0, min(pos_limits['RB'], remaining) + 1):
            remaining2 = remaining - r
            for w in range(0, min(pos_limits['WR'], remaining2) + 1):
                t = remaining2 - w
                if 0 <= t <= pos_limits['TE']:
                    # 分配每个元素的位置
                    all_positions = list(range(target_length))
                    # 选QB的位置
                    for q_pos in itertools.combinations(all_positions, q):
                        leftover_pos = [p for p in all_positions if p not in q_pos]
                        # 选RB的位置
                        for r_pos in itertools.combinations(leftover_pos, r):
                            leftover_pos2 = [p for p in leftover_pos if p not in r_pos]
                            # 选WR的位置
                            for w_pos in itertools.combinations(leftover_pos2, w):
                                # 剩余位置填充TE
                                combo = [''] * target_length
                                for p in q_pos:
                                    combo[p] = 'QB'
                                for p in r_pos:
                                    combo[p] = 'RB'
                                for p in w_pos:
                                    combo[p] = 'WR'
                                for p in leftover_pos2:
                                    if p not in w_pos:
                                        combo[p] = 'TE'
                                result.append(tuple(combo))
    return result

combos = generate_unique_permutations()

关键注意事项

即使是高效方法,生成18长度的唯一排列数量依然极大(比如选3QB、5RB、7WR、3TE的情况下,排列数约为1.3×10¹⁰),会占用巨量内存和时间。如果你的需求不是必须生成所有排列,建议调整方向:

  • 若只需计数,直接用组合数学公式:总排列数 = 18! / (q!×r!×w!×t!)(其中q、r、w、t为各元素选取数量,满足q+r+w+t=18且不超过各自上限)
  • 若只需抽样,可通过随机分配位置的方式生成唯一排列,无需遍历全部

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 01:15:30