【问题标题】:Create all possible binary permutations with a given number of ones in Java在 Java 中创建具有给定数量的二进制排列的所有可能的二进制排列
【发布时间】:2015-07-13 20:18:47
【问题描述】:

我想在 Java 中找到所有可能的具有给定数量的二进制排列:

  • x 是每个序列中所需的个数
  • n 是每个序列的所需长度

举个例子:

x=2, n=4

输出:1100, 0011, 1010, 1001, 0101, 0110

我正在寻找一种优雅而快速的方法来做到这一点。你能帮助我吗? 我已经在Print list of binary permutations 中测试了 eboix 解决方案,但不幸的是它太慢了,因为此示例中的算法正在搜索所有2^n 二进制排列。 我想查找长度为50100 的序列。

【问题讨论】:

  • 您正在寻找combinations,而不是排列。你想一次拿 n 个东西 k。如果您想要所有设置了 2 位的 4 位数字,您希望 4 个事物的组合一次取 2 个。至少有一个 Java 组合库可以为您完成。
  • 问题是:我需要“一些”具有 100 位长度和给定数量的序列。也许我应该以其他方式创建它们,因为它们中有太多 100 位长度或更多。我只需要不相似的序列。不相似的意思是序列,他们有不同的运行次数。例如:如果 x=2,n=100。我想找到一个运行一次的序列:1100000....,一个运行两次 1010000.... 如果 x=3,n = 100:我想找到一个运行 1 次的序列:1110000...,一个两次运行 101100000.... 和一次运行三个 1010100000.... 等等。
  • @Jim Mischel,我去图书馆看看,谢谢。

标签: java algorithm permutation


【解决方案1】:

首先,您缺少 0110 作为输出案例。

n choose x 的可能性相当直观。您在n 总插槽中找到x 相同项目的所有有效排列。所以你可以在O(1)中找到序列的总数。

作为提示,请尝试简单地查找由x 后跟n - x 零组成的位串的所有排列。

要专门解决该问题,请尝试创建一个递归算法,该算法在每次 ith 迭代时决定包括 10。如果包含1,则需要减少可用于字符串其余部分的1's 计数。

【讨论】:

    【解决方案2】:

    实际上,可能有一种优雅的方式,但没有快速的方式来做到这一点。字符串排列的数量由二项式系数给出(参见https://en.wikipedia.org/wiki/Binomial_coefficient)。例如,x=10, n= 50 给出了超过 1000 万个不同的字符串。

    【讨论】:

      【解决方案3】:

      这只是一个基本版本,可以生成您想要的输出。请努力使其更准确/更高效 -

      这不会生成所有组合,但您会知道如何做。当然,对于由此生成的所有可能组合,您必须生成所有其他可能的组合。

      public class Test {
          static int iter = 0;
          public static void main(String args[]){
              int n = 50;
              int x = 5;
              byte[] perms = new byte[n];
              for(int i=0; i<x; i++){
                  perms[i] = 1;
              }
              print(perms);
              for(int j=x-1; j>=0; j--){
                  for(int i=1; i<(n/2-j); i++){
                      iter++;
                      swap(perms, j, i);
                  }
              }
          }
          public static void swap(byte[] perms, int pos, int by){
              byte val = perms[pos+by];
              perms[pos+by] = perms[pos];
              perms[pos] = val;
              print(perms);
              val = perms[pos+by];
              perms[pos+by] = perms[pos];
              perms[pos] = val;
          }
      
          public static void print(byte[] perms){
              System.out.println("iter = "+iter);
              for(int i=0; i<perms.length; i++){
                  System.out.print(perms[i]);
              }
              System.out.println();
              for(int i=perms.length-1; i>=0; i--){
                  System.out.print(perms[i]);
              }
              System.out.println();
          }
      }
      

      【讨论】:

      • 我将尝试发布完整工作的递归代码,当我有时间来处理这个问题时。 -谢谢。
      【解决方案4】:

      给你的另一个灵感。一个有效的肮脏版本。它分配额外的数组空间(你应该调整size)并在末尾使用String Set来删除重复。

      public static void main(String[] args) {
          int x = 2;
          int n = 4;
      
          Set<BigInteger> result = new LinkedHashSet<>();
          for (int j = x; j > 0; j--) {
              Set<BigInteger> a = new LinkedHashSet<>();
      
              for (int i = 0; i < n - j + 1; i++) {
                  if (j == x) {
                      a.add(BigInteger.ZERO.flipBit(i));
                  } else {
                      for (BigInteger num : result) {
                          if (num != null && !num.testBit(i) && (i >= (n - j) || num.getLowestSetBit() >= i-1))
                              a.add(num.setBit(i));
                      }
                  }
              }
              result = a;
          }
      
          String zeros = new String(new char[n]).replace("\0", "0");
          for (BigInteger i : result) {
              String binary = i.toString(2);
              System.out.println(zeros.substring(0, n - binary.length()) + binary);
          }
      
      }
      

      编辑:将原始版本更改为使用 BigInteger 来支持更大的 n,x 值。

      【讨论】:

      • 完美的尺寸公式是size = size * (n + 1 - x);。享受吧!
      • 我改变了初始算法 - 不再有地图或集合,只有纯 int[] 性能!
      • 感谢发帖!此代码似乎适用于 32 以下的任何 x 和 n 值。但如果 n = 33 或更大,则输出会出错。比如n=33,x=1,最后输出的不是想要的10000.....
      • 修复了这个问题 - 现在需要很长时间,并且应该适用于最多 64 的 n。如果您需要更多,则需要更多的努力。
      • 非常感谢!是的 - 现在它适用于 n 值小于 65,但 x 值大于 1,您将在“a[pos++] = num | (long) 1
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-20
      • 1970-01-01
      • 1970-01-01
      • 2021-10-20
      • 1970-01-01
      • 2014-03-15
      相关资源
      最近更新 更多