【问题标题】:Java: Looking for an algorithm for permutationJava:寻找置换算法
【发布时间】:2015-07-11 13:00:30
【问题描述】:

假设我有一个数组。

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();
    }

}

效果很好。

【问题讨论】:

  • 到目前为止你得到了什么?
  • @ultranaut 你的意思是实现?
  • 是的,你有没有试过什么?如果是这样,它不起作用吗?
  • 我的 impl 不起作用。
  • 看起来您要的是所有有序子集,而不是排列。您应该使用递归算法。

标签: java algorithm combinatorics


【解决方案1】:

我最近编写了 Java 类,用于在任何 Comparable 对象上生成排列。看看我的github页面here上的代码,很少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 类。现在我们需要知道如何获得给定集合的所有子集。在下面的代码中,我使用 bitmasks 完成了这项工作。

请查看以下链接,了解如何使用 位掩码 生成给定集合的所有子集:

这是您需要的:

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 类周围,并让它完成工作。

【讨论】:

  • 太复杂了。我给出的算法很简单。此算法需要另一个库(或该代码的副本)的依赖项,并且不适用于超过 32 个整数。不过它有懒惰的优点。
【解决方案2】:

一个正常的排列生成算法应该可以工作,您需要做的就是调整它以打印排列的前缀。

我最近给了一个answer for permutations,但它是在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 中的相同算法,它适用于我,看起来你的尝试有错误(例如从完成中删除,设置为 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);
  }
}

【讨论】:

  • 我添加了一个 py 而不是 java,因为我强烈怀疑这可能是家庭作业。此外,py 很容易获得......
  • @barbara:我可以询问家庭作业,IMO。只是不想破坏你的学习经验,以防万一,即我没有指责你任​​何事情。事实上,我很高兴看到您实际上正在与回答您问题的人互动!我看到很多人只是问一个问题,而不是承认其他试图帮助他们的人所付出的努力。
  • 请注意,Java 的 print 方法假定为数字(这样做是为了消除讨厌的滚动条)。
  • 您的解决方案似乎不起作用。尝试使用new ArrayList&lt;String&gt;(Arrays.asList("A", "B", "C")); 运行它,它会打印[] [A] [AB] [ABC] [AC] [ACB] [C] [CA] [CAB] [CB] [CBA] [A] [AC] [ACB] [AB] [ABC]
  • @barbara:看起来我放了一个旧版本。 Integer c = remaining.get(j) 行必须是 Integer c = sorted.get(j)。固定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-17
  • 2013-08-13
  • 1970-01-01
  • 1970-01-01
  • 2011-05-04
  • 2011-01-29
相关资源
最近更新 更多