有人可以解释一个好的算法,以有效的方式找到给定数字集的所有排列吗?
答案 0 :(得分:8)
最简单的方法是递归方法,即可执行伪代码;
def permute(theseq):
if len(theseq) <= 1:
yield theseq
return
for i in range(len(theseq)):
theseq[0], theseq[i] = theseq[i], theseq[0]
for subperm in permute(theseq[1:]):
yield theseq[:1] + subperm
theseq[0], theseq[i] = theseq[i], theseq[0]
如果您不熟悉executable pseudocode,则表示[1:]
和[:1]
表示“切片”(分别是“除了第一个以外的所有”和“仅仅是第一个”) “),两个相同的任务执行”交换第0和第i项“和”将它们放回原位“的任务(即再次交换它们;-)。 yield
表示“提供此结果,但在迭代时准备好继续”,而return
表示“我们都已完成,再见!”。
在不同的性能轴上有一些更好的方法,但第一个里程碑是确保你完全熟悉基本的递归方法并彻底理解它 - 所以我现在停在这里。如果你完全理解这种方法,为什么它会很好,花花公子,和如何以及为什么它在性能上看起来不是最佳,我会很高兴 扩展这个答案! - )
答案 1 :(得分:6)
答案 2 :(得分:3)
我的c#实现了Alex的伪代码:
private int length;
private List<List<string>> permutations;
public List<List<string>> Generate(List<string> list)
{
length = list.Count;
permutations = new List<List<string>>();
foreach(List<string> subperms in Recursive(list))
permutations.Add(subperms);
return permutations;
}
private List<List<string>> Recursive(List<string> list)
{
List<List<string>> subperms = new List<List<string>>();
if (list.Count <= 1)
{
subperms.Add(list);
return subperms;
}
for (int i = 0; i < list.Count; i++)
{
string temp = list[0];
list[0] = list[i];
list[i] = temp;
List<string> tail = new List<string>(list);
tail.RemoveAt(0);
List<string> head = new List<string>();
head.Add(list[0]);
foreach (List<string> subperm in Recursive(tail))
{
List<string> headCopy = new List<string>(head);
headCopy.AddRange(subperm);
if (headCopy.Count == length)
permutations.Add(headCopy);
else
subperms.Add(headCopy);
}
temp = list[0];
list[0] = list[i];
list[i] = temp;
}
return subperms;
}
答案 3 :(得分:0)
你看过Knuth'计算机程序设计的艺术'吗?第3卷,排序和搜索涵盖了它,这是有道理的,因为排序会创建数据的特定排列。
警惕找到所有组合或排列的组合(和置换)算法。它们具有非常昂贵的Big-O表示法成本。