Java: 寻找排列的算法
Java: Looking for an algorithm for permutation
假设我有一个数组。
String[] arr = {"a", "b", "c"};
我需要得到所有可能的组合,像这样:
a
a b
a c
a b c
a c b
b
b a
b c
b a c
b c a
c
c a
c b
c a b
c b a
我应该使用哪种快速算法来获得所有组合?
UPD
public static void permute(List<Integer> done, List<Integer> remaining {
remaining.removeAll(Collections.<Integer>singletonList(null));
done.removeAll(Collections.<Integer>singletonList(null));
System.out.println(done);
if (remaining.size() == 0) {
return;
}
for (int i = 0; i < remaining.size(); i++) {
Integer e = remaining.get(i);
done.add(e);
remaining.set(i, null);
permute(done, remaining);
remaining.add(e);
done.set(i, null);
}
}
输出
[]
[1]
[1, 2]
[1, 2, 3]
[1, 2, 3, 4]
[2, 3, 4, 3]
[2, 3, 4, 3, 4]
[4, 3, 4, 3]
[4, 3, 4, 3, 4]
[4, 3, 4, 3, 4, 2]
[3, 4, 3, 4, 2, 4]
[3, 4, 3, 4, 2, 4, 2]
[3, 4, 2, 4, 2, 3]
[3, 4, 2, 4, 2, 3, 2]
[3, 4, 2, 4, 2, 3, 2, 4]
[4, 2, 4, 2, 3, 2, 4, 2]
[4, 2, 4, 2, 3, 2, 4, 2, 4]
[2, 3, 2, 4, 2, 4, 2]
[2, 3, 2, 4, 2, 4, 2, 4]
[2, 3, 2, 4, 2, 4, 2, 4, 3]
[2, 3, 2, 4, 2, 4, 2, 4, 3, 1]
[3, 2, 4, 2, 4, 2, 4, 3, 1, 3]
[3, 2, 4, 2, 4, 2, 4, 3, 1, 3, 1]
[4, 2, 4, 2, 4, 3, 1, 3, 1, 3]
[4, 2, 4, 2, 4, 3, 1, 3, 1, 3, 1]
[4, 2, 4, 2, 4, 3, 1, 3, 1, 3, 1, 4]
[2, 4, 2, 4, 3, 1, 3, 1, 3, 1, 4, 1]
[2, 4, 2, 4, 3, 1, 3, 1, 3, 1, 4, 1, 4]
[2, 4, 3, 1, 3, 1, 3, 1, 4, 1, 4, 3]
[2, 4, 3, 1, 3, 1, 3, 1, 4, 1, 4, 3, 4]
[2, 4, 3, 1, 3, 1, 3, 1, 4, 1, 4, 3, 4, 1]
[4, 3, 1, 3, 1, 3, 1, 4, 1, 4, 3, 4, 1, 4]
[4, 3, 1, 3, 1, 3, 1, 4, 1, 4, 3, 4, 1, 4, 1]
[3, 1, 3, 1, 4, 1, 4, 3, 4, 1, 4, 1, 3]
[3, 1, 3, 1, 4, 1, 4, 3, 4, 1, 4, 1, 3, 1]
[3, 1, 3, 1, 4, 1, 4, 3, 4, 1, 4, 1, 3, 1, 4]
[3, 1, 3, 1, 4, 1, 4, 3, 4, 1, 4, 1, 3, 1, 4, 2]
[1, 3, 1, 4, 1, 4, 3, 4, 1, 4, 1, 3, 1, 4, 2, 4]
[1, 3, 1, 4, 1, 4, 3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2]
[1, 4, 1, 4, 3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2, 4]
[1, 4, 1, 4, 3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2, 4, 2]
[1, 4, 1, 4, 3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1]
[4, 1, 4, 3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2]
[4, 1, 4, 3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1]
[4, 3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4]
[4, 3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1]
[4, 3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2]
[3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1]
[3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2]
[4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3]
[4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2]
[4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1]
[4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4]
[1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1]
[1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4]
[1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4, 1]
[1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4, 1, 4]
[1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4, 1, 4, 2]
[4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4, 1, 4, 2, 4]
[4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4, 1, 4, 2, 4, 2]
[4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4, 1, 4, 2, 4, 2, 1]
[4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4, 1, 4, 2, 4, 2, 1, 2]
[4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4, 1, 4, 2, 4, 2, 1, 2, 4]
[2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4, 1, 4, 2, 4, 2, 1, 2, 4, 2]
[2, 4
, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4, 1, 4, 2, 4, 2, 1, 2, 4, 2, 4]
UPD3
我找到了一些代码并重新设计了它。所以我得到了这个:
public class Permutations {
public static void main(String[] args) {
Set<String> combos = new Permutations().combos("1", "2", "3", "4", "5");
for (String combo : combos) {
for (char e : combo.toCharArray()){
System.out.printf("[%s]", e);
}
System.out.println();
}
}
public Set<String> combos(String... input) {
Set<String> set = new TreeSet<>();
combos(input, set, input.length, new StringBuffer());
return set;
}
private void combos(String[] input, Set<String> set, int len, StringBuffer buf) {
if (len == 0) {
String elem = unique(buf.toString());
set.add(elem);
} else {
for (String t : input) {
buf.append(t);
combos(input, set, len - 1, buf);
buf.deleteCharAt(buf.length() - 1);
}
}
}
private String unique(String input) {
StringBuilder unique = new StringBuilder();
for (int i = 0; i < input.length(); i++) {
String si = input.substring(i, i + 1);
if (unique.indexOf(si) == -1)
unique.append(si);
}
return unique.toString();
}
}
它工作正常。
正常的排列生成算法应该可以工作,您需要做的就是调整它以打印排列的前缀。
我最近给了一个,但它在python。应该很容易转换为 Java.
这是代码,添加了前缀打印的调整:
def permute(done, remaining):
print done # Move this to the if below to print only full permutations.
if not remaining:
return
sorted_rem = sorted(remaining)
l = len(sorted_rem)
for i in xrange(0, l):
c = sorted_rem[i]
# Move to c to done portion.
done.append(c)
remaining.remove(c)
# Permute the remaining
permute(done, remaining)
# Put c back.
remaining.append(c)
# Remove from done.
del done[-1]
def main():
permute([], range(1,4))
if __name__ == "__main__":
main()
这是输出:
[]
[1]
[1, 2]
[1, 2, 3]
[1, 3]
[1, 3, 2]
[2]
[2, 1]
[2, 1, 3]
[2, 3]
[2, 3, 1]
[3]
[3, 1]
[3, 1, 2]
[3, 2]
[3, 2, 1]
这里是 Java 中相同的算法,它对我有用,看起来你的尝试有错误(例如从 done 中删除,设置为 null 而不是删除)。
class Permutation {
public static void print(ArrayList<Integer> array) {
System.out.print("[");
for (Integer elem: array) {
System.out.print(elem.toString());
}
System.out.println("]");
}
public static void Permute(ArrayList<Integer> done,
ArrayList<Integer> remaining) {
print(done);
if (remaining.size() == 0) {
return;
}
ArrayList<Integer> sorted = new ArrayList<Integer>(remaining);
Collections.sort(sorted);
for (int j = 0; j < remaining.size(); j++) {
Integer c = sorted.get(j);
remaining.remove(c);
done.add(c);
Permute(done, remaining);
done.remove(c);
remaining.add(0, c);
}
}
public static void main(String[] args) {
ArrayList<Integer> remaining =
new ArrayList<Integer>(Arrays.asList(1,2,3,4));
ArrayList<Integer> done = new ArrayList<Integer>();
Permute(done, remaining);
}
}
我最近写了 Java class 用于在任何 Comparable
对象上生成排列。查看我的 github 页面 here, and few examples 上的代码,了解如何使用它。
这是其中一个示例 c/p:
public static void main(final String[] args) {
Permutation<Integer> permutation = new Permutation<>(1, 2, 3);
do {
System.out.println(permutation);
} while (permutation.nextPermutation());
}
这将打印 1, 2, 3
数组的所有排列。
根据你的问题我了解到你需要:给定集合的每个子集的所有排列。
有关获取给定集合的所有排列的部分已完成 - 使用 Permutation
class。现在我们需要知道如何获得给定集合的所有子集。在下面的代码中,我使用 bitmasks.
完成了该操作
请查看下面的一些链接,了解如何使用 位掩码 生成给定集合的所有子集:
- Printing all possible subsets of a list
- http://www.ugrad.cs.ubc.ca/~cs490/sec202/notes/intro/bitmask.pdf
这是您需要的:
public static void main(final String[] args) {
List<String> list = Arrays.asList("a", "b", "c");
int numberOfSubsets = 1 << list.size();
for (int mask = 0; mask < numberOfSubsets; mask++) {
List<String> subset = new ArrayList<>();
int N = mask;
for (int i = 0; i < list.size(); i++) {
if (N % 2 == 1)
subset.add(list.get(i));
N /= 2;
}
Permutation<String> permutation = new Permutation<>(subset);
do {
System.out.println(permutation);
} while (permutation.nextPermutation());
}
}
我们将给定集合的每个子集包裹在 Permutation
class 周围并让它完成工作。
假设我有一个数组。
String[] arr = {"a", "b", "c"};
我需要得到所有可能的组合,像这样:
a
a b
a c
a b c
a c b
b
b a
b c
b a c
b c a
c
c a
c b
c a b
c b a
我应该使用哪种快速算法来获得所有组合?
UPD
public static void permute(List<Integer> done, List<Integer> remaining {
remaining.removeAll(Collections.<Integer>singletonList(null));
done.removeAll(Collections.<Integer>singletonList(null));
System.out.println(done);
if (remaining.size() == 0) {
return;
}
for (int i = 0; i < remaining.size(); i++) {
Integer e = remaining.get(i);
done.add(e);
remaining.set(i, null);
permute(done, remaining);
remaining.add(e);
done.set(i, null);
}
}
输出
[]
[1]
[1, 2]
[1, 2, 3]
[1, 2, 3, 4]
[2, 3, 4, 3]
[2, 3, 4, 3, 4]
[4, 3, 4, 3]
[4, 3, 4, 3, 4]
[4, 3, 4, 3, 4, 2]
[3, 4, 3, 4, 2, 4]
[3, 4, 3, 4, 2, 4, 2]
[3, 4, 2, 4, 2, 3]
[3, 4, 2, 4, 2, 3, 2]
[3, 4, 2, 4, 2, 3, 2, 4]
[4, 2, 4, 2, 3, 2, 4, 2]
[4, 2, 4, 2, 3, 2, 4, 2, 4]
[2, 3, 2, 4, 2, 4, 2]
[2, 3, 2, 4, 2, 4, 2, 4]
[2, 3, 2, 4, 2, 4, 2, 4, 3]
[2, 3, 2, 4, 2, 4, 2, 4, 3, 1]
[3, 2, 4, 2, 4, 2, 4, 3, 1, 3]
[3, 2, 4, 2, 4, 2, 4, 3, 1, 3, 1]
[4, 2, 4, 2, 4, 3, 1, 3, 1, 3]
[4, 2, 4, 2, 4, 3, 1, 3, 1, 3, 1]
[4, 2, 4, 2, 4, 3, 1, 3, 1, 3, 1, 4]
[2, 4, 2, 4, 3, 1, 3, 1, 3, 1, 4, 1]
[2, 4, 2, 4, 3, 1, 3, 1, 3, 1, 4, 1, 4]
[2, 4, 3, 1, 3, 1, 3, 1, 4, 1, 4, 3]
[2, 4, 3, 1, 3, 1, 3, 1, 4, 1, 4, 3, 4]
[2, 4, 3, 1, 3, 1, 3, 1, 4, 1, 4, 3, 4, 1]
[4, 3, 1, 3, 1, 3, 1, 4, 1, 4, 3, 4, 1, 4]
[4, 3, 1, 3, 1, 3, 1, 4, 1, 4, 3, 4, 1, 4, 1]
[3, 1, 3, 1, 4, 1, 4, 3, 4, 1, 4, 1, 3]
[3, 1, 3, 1, 4, 1, 4, 3, 4, 1, 4, 1, 3, 1]
[3, 1, 3, 1, 4, 1, 4, 3, 4, 1, 4, 1, 3, 1, 4]
[3, 1, 3, 1, 4, 1, 4, 3, 4, 1, 4, 1, 3, 1, 4, 2]
[1, 3, 1, 4, 1, 4, 3, 4, 1, 4, 1, 3, 1, 4, 2, 4]
[1, 3, 1, 4, 1, 4, 3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2]
[1, 4, 1, 4, 3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2, 4]
[1, 4, 1, 4, 3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2, 4, 2]
[1, 4, 1, 4, 3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1]
[4, 1, 4, 3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2]
[4, 1, 4, 3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1]
[4, 3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4]
[4, 3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1]
[4, 3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2]
[3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1]
[3, 4, 1, 4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2]
[4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3]
[4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2]
[4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1]
[4, 1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4]
[1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1]
[1, 3, 1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4]
[1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4, 1]
[1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4, 1, 4]
[1, 4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4, 1, 4, 2]
[4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4, 1, 4, 2, 4]
[4, 2, 4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4, 1, 4, 2, 4, 2]
[4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4, 1, 4, 2, 4, 2, 1]
[4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4, 1, 4, 2, 4, 2, 1, 2]
[4, 2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4, 1, 4, 2, 4, 2, 1, 2, 4]
[2, 4, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4, 1, 4, 2, 4, 2, 1, 2, 4, 2]
[2, 4
, 2, 1, 2, 1, 4, 1, 2, 1, 2, 3, 2, 1, 4, 1, 4, 1, 4, 2, 4, 2, 1, 2, 4, 2, 4]
UPD3
我找到了一些代码并重新设计了它。所以我得到了这个:
public class Permutations {
public static void main(String[] args) {
Set<String> combos = new Permutations().combos("1", "2", "3", "4", "5");
for (String combo : combos) {
for (char e : combo.toCharArray()){
System.out.printf("[%s]", e);
}
System.out.println();
}
}
public Set<String> combos(String... input) {
Set<String> set = new TreeSet<>();
combos(input, set, input.length, new StringBuffer());
return set;
}
private void combos(String[] input, Set<String> set, int len, StringBuffer buf) {
if (len == 0) {
String elem = unique(buf.toString());
set.add(elem);
} else {
for (String t : input) {
buf.append(t);
combos(input, set, len - 1, buf);
buf.deleteCharAt(buf.length() - 1);
}
}
}
private String unique(String input) {
StringBuilder unique = new StringBuilder();
for (int i = 0; i < input.length(); i++) {
String si = input.substring(i, i + 1);
if (unique.indexOf(si) == -1)
unique.append(si);
}
return unique.toString();
}
}
它工作正常。
正常的排列生成算法应该可以工作,您需要做的就是调整它以打印排列的前缀。
我最近给了一个
这是代码,添加了前缀打印的调整:
def permute(done, remaining):
print done # Move this to the if below to print only full permutations.
if not remaining:
return
sorted_rem = sorted(remaining)
l = len(sorted_rem)
for i in xrange(0, l):
c = sorted_rem[i]
# Move to c to done portion.
done.append(c)
remaining.remove(c)
# Permute the remaining
permute(done, remaining)
# Put c back.
remaining.append(c)
# Remove from done.
del done[-1]
def main():
permute([], range(1,4))
if __name__ == "__main__":
main()
这是输出:
[]
[1]
[1, 2]
[1, 2, 3]
[1, 3]
[1, 3, 2]
[2]
[2, 1]
[2, 1, 3]
[2, 3]
[2, 3, 1]
[3]
[3, 1]
[3, 1, 2]
[3, 2]
[3, 2, 1]
这里是 Java 中相同的算法,它对我有用,看起来你的尝试有错误(例如从 done 中删除,设置为 null 而不是删除)。
class Permutation {
public static void print(ArrayList<Integer> array) {
System.out.print("[");
for (Integer elem: array) {
System.out.print(elem.toString());
}
System.out.println("]");
}
public static void Permute(ArrayList<Integer> done,
ArrayList<Integer> remaining) {
print(done);
if (remaining.size() == 0) {
return;
}
ArrayList<Integer> sorted = new ArrayList<Integer>(remaining);
Collections.sort(sorted);
for (int j = 0; j < remaining.size(); j++) {
Integer c = sorted.get(j);
remaining.remove(c);
done.add(c);
Permute(done, remaining);
done.remove(c);
remaining.add(0, c);
}
}
public static void main(String[] args) {
ArrayList<Integer> remaining =
new ArrayList<Integer>(Arrays.asList(1,2,3,4));
ArrayList<Integer> done = new ArrayList<Integer>();
Permute(done, remaining);
}
}
我最近写了 Java class 用于在任何 Comparable
对象上生成排列。查看我的 github 页面 here, and few examples 上的代码,了解如何使用它。
这是其中一个示例 c/p:
public static void main(final String[] args) {
Permutation<Integer> permutation = new Permutation<>(1, 2, 3);
do {
System.out.println(permutation);
} while (permutation.nextPermutation());
}
这将打印 1, 2, 3
数组的所有排列。
根据你的问题我了解到你需要:给定集合的每个子集的所有排列。
有关获取给定集合的所有排列的部分已完成 - 使用 Permutation
class。现在我们需要知道如何获得给定集合的所有子集。在下面的代码中,我使用 bitmasks.
请查看下面的一些链接,了解如何使用 位掩码 生成给定集合的所有子集:
- Printing all possible subsets of a list
- http://www.ugrad.cs.ubc.ca/~cs490/sec202/notes/intro/bitmask.pdf
这是您需要的:
public static void main(final String[] args) {
List<String> list = Arrays.asList("a", "b", "c");
int numberOfSubsets = 1 << list.size();
for (int mask = 0; mask < numberOfSubsets; mask++) {
List<String> subset = new ArrayList<>();
int N = mask;
for (int i = 0; i < list.size(); i++) {
if (N % 2 == 1)
subset.add(list.get(i));
N /= 2;
}
Permutation<String> permutation = new Permutation<>(subset);
do {
System.out.println(permutation);
} while (permutation.nextPermutation());
}
}
我们将给定集合的每个子集包裹在 Permutation
class 周围并让它完成工作。