python - 使用回溯的唯一排列

标签 python permutation backtracking

我试图在寻找唯一排列的问题中使用回溯法。我写了这个:

def f(A, start, end):
    if start == end - 1:
        print(A)
    else:
        for idx in range(start, end):
            if idx != start and A[idx] == A[start]:
                continue
            A[idx], A[start] = A[start], A[idx]
            f(A, start + 1, end)

这个例子有效

A = [2, 3, 2]
f(A, 0, len(A))

[2, 3, 2]
[2, 2, 3]
[3, 2, 2]

这个不行

A = [2, 2, 1, 1]
f(A, 0, len(A))

[2, 2, 1, 1]
[2, 1, 2, 1]
[2, 1, 1, 2]
[2, 2, 1, 1] #unwanted duplicate!
[1, 2, 2, 1]
[1, 2, 1, 2]
[1, 1, 2, 2]
[1, 2, 2, 1]
[1, 2, 1, 2]
[2, 2, 1, 1]
[2, 1, 2, 1]
[2, 1, 1, 2]
[2, 2, 1, 1]

为什么结果中仍然有重复项?

最佳答案

在过滤中,您使用一对一检查。因此,但是从超过三个元素的那一刻起,这将起作用。

这是因为,您可以在多次(实际)交换后获得相同的排列。例如:

[1   ,2(1),2(2),3   ] -> swap 1 with 3
[1   ,3,   2(2),2(1)] -> swap 1 with 2
[1   ,2(2),3   ,2(1)] -> swap 2 with 3
[1   ,2(2),2(1),3   ]

如您所见,排列是相同的(但两个 two 的来源不同)。所以我们间接交换了这两个。

不过,没必要搞得那么复杂。有两种方法可能适用于此:

  • 对列表进行排序,并强制执行约束,即您只能发出字典顺序上比前一个更多的列表;和
  • 首先计算出现次数(使用 Counter,然后确保根据计数器发出)。

后者将运行得更快,因为它不会生成必须忽略的排列。

一个示例实现可以是:

from collections import Counter

def f(lst):
    def g(l,c,n):
        if n <= 0:
            yield tuple(l)
        else:
            for k,v in c.items():
                if v > 0:
                    c[k] -= 1
                    l.append(k)
                    for cfg in g(l,c,n-1):
                        yield cfg
                    l.pop()
                    c[k] += 1
    for cfg in g([],Counter(lst),len(lst)):
        yield cfg

这给出:

>>> list(f([1,1,2,2]))
[(1, 1, 2, 2), (1, 2, 1, 2), (1, 2, 2, 1), (2, 1, 1, 2), (2, 1, 2, 1), (2, 2, 1, 1)]
>>> list(f([1,1,2,2,3]))
[(1, 1, 2, 2, 3), (1, 1, 2, 3, 2), (1, 1, 3, 2, 2), (1, 2, 1, 2, 3), (1, 2, 1, 3, 2), (1, 2, 2, 1, 3), (1, 2, 2, 3, 1), (1, 2, 3, 1, 2), (1, 2, 3, 2, 1), (1, 3, 1, 2, 2), (1, 3, 2, 1, 2), (1, 3, 2, 2, 1), (2, 1, 1, 2, 3), (2, 1, 1, 3, 2), (2, 1, 2, 1, 3), (2, 1, 2, 3, 1), (2, 1, 3, 1, 2), (2, 1, 3, 2, 1), (2, 2, 1, 1, 3), (2, 2, 1, 3, 1), (2, 2, 3, 1, 1), (2, 3, 1, 1, 2), (2, 3, 1, 2, 1), (2, 3, 2, 1, 1), (3, 1, 1, 2, 2), (3, 1, 2, 1, 2), (3, 1, 2, 2, 1), (3, 2, 1, 1, 2), (3, 2, 1, 2, 1), (3, 2, 2, 1, 1)]

关于python - 使用回溯的唯一排列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44161971/

相关文章:

c++ - 重复组合计数

c++ - 魔方回溯和递归 C++

algorithm - 寻找最小的顶点子集 - 回溯?

python - Pandas 创建一个数据框,其条目是另一个数据框的行之间的关系?

python - 在 python 中按特定顺序对元素进行排序

python - 从字典中输出python中的大矩阵

c++ - 计算排列的逆下降

python - 如何迭代字符串中的某些字符和其他字符在python中保持相同位置

c - 带有递归和回溯的骑士​​之旅代码

python - 如何使用线程获取数据并将数据写入同一个文本文件