【问题标题】:Java. How to generate all integers with certain number of 1's and 0's in it? [closed]爪哇。如何生成其中包含一定数量的 1 和 0 的所有整数? [关闭]
【发布时间】:2015-08-21 00:04:40
【问题描述】:

使用 Java 解决此问题的最有效方法是什么?
例如: 生成所有包含 三个 1'的数字s & 两个 0

解决方案:

11100
11010
10110
01110
11001
10101
01101
10011
01011
00111

【问题讨论】:

标签: java arrays integer bit-manipulation permutation


【解决方案1】:

你可以使用递归:

public static void generateBits(String s, int ones, int zeros)
{
    if(ones > 0)
        generateBits(s + "1", ones - 1, zeros);
    if(zeros > 0)
        generateBits(s + "0", ones, zeros - 1);

    if(ones == 0 && zeros == 0)
        System.out.println(s);
}

该函数接受部分完成的字符串和剩余多少个 1 和 0 的计数,然后递归添加 1 和添加 0 的情况(如果还有剩余)。当没有更多可以添加时,它会打印字符串。这将生成每个数字一次,没有重复。如果需要,您可以将字符串解析为数字,而不是将其打印出来。像这样调用:

generateBits("", 3, 2);

我使用String 类型来允许前导零,同时保持简单,但正如@Aivean 在评论中指出的那样,字符串连接可能很昂贵。这是另一种更有效的解决方案,它使用 long,并在打印出值时转换为带有前导零的二进制字符串表示:

public static void generateBits(long val, int ones, int zeros, int len)
{
    if(ones > 0)
        generateBits((val << 1) + 1L, ones - 1, zeros, len + 1);
    if(zeros > 0)
        generateBits(val << 1, ones, zeros - 1, len + 1);

    if(ones == 0 && zeros == 0)
        System.out.println(String.format("%"+len+"s", Long.toBinaryString(val)).replace(' ', '0'));
} 

在顶层调用时需要传入0作为长度。你可以这样称呼它:

generateBits(0L, 3, 2, 0);

【讨论】:

  • 你有正确的方法,但我反对使用字符串连接。它不能被称为“有效”的方法。考虑用 longs 或 BitSets 上的位操作替换字符串连接:s &lt;&lt;= 1; generateBits(s | 1L, ones - 1, zeros);
【解决方案2】:

这是基于BitSet 的非递归解决方案:

static void genCombinations(int n, int k) {
    BitSet bs = new BitSet(n);
    bs.set(0, k);
    while(true) {
        // output
        for(int i=0; i<n; i++)
            System.out.print(bs.get(i) ? "1" : "0");
        System.out.println();
        int b = bs.previousClearBit(n-1); // the last zero
        int b1 = bs.previousSetBit(b); // the last one before that zero
        if(b1 == -1)
            return;
        bs.clear(b1);
        bs.set(b1+1, b1+(n-b)+1);
        bs.clear(b1+(n-b)+1, n);
    }
}

public static void main(String[] args) {
    genCombinations(5, 3);
}

这种迭代方法有时更方便,因为您可以像这样创建Iterable 类:

public static class Combinations implements Iterable<String> {
    private int n;
    private int k;

    public Combinations(int n, int k) {
        this.n = n;
        this.k = k;
    }

    @Override
    public Iterator<String> iterator() {
        return new Iterator<String>() {
            BitSet bs = new BitSet(n);

            {
                bs.set(0, k);
            }

            @Override
            public boolean hasNext() {
                return bs != null;
            }

            @Override
            public String next() {
                char[] res = new char[n];
                for (int i = 0; i < n; i++)
                    res[i] = bs.get(i) ? '1' : '0';
                int b = bs.previousClearBit(n - 1);
                int b1 = bs.previousSetBit(b);
                if (b1 == -1)
                    bs = null;
                else {
                    bs.clear(b1);
                    bs.set(b1 + 1, b1 + (n - b) + 1);
                    bs.clear(b1 + (n - b) + 1, n);
                }
                return new String(res);
            }
        };
    }
}

并在for循环中使用它:

for(String comb : new Combinations(5, 3)) {
    System.out.println(comb);
}

【讨论】:

    【解决方案3】:

    要获得带有前导零的int,您必须将其生成为String。这是没有重复的最快方法:

    public final class Permutator {
    
      public static void main(String[] args) {
        new Permutator(3, 5);
      }
    
      public Permutator(int numberOfOnes, int length) {
        StringBuilder start = new StringBuilder();
        for (int x = 0; x < length; x++)
          start.append('0');
        permutate(numberOfOnes, 0, 0, length, start);
        System.exit(0);
      }
    
      public void permutate(int numberOfOnes, int first, int depth, int length, StringBuilder base) {
        for (int x = first; x < length; x++) {
          StringBuilder onesAndZeros = new StringBuilder(base.toString());
          onesAndZeros.setCharAt(x, '1');
          if (numberOfOnes == depth + 1)
            System.out.println(onesAndZeros.toString());
          else
            permutate(numberOfOnes, x + 1, depth + 1, length, onesAndZeros);
        }
      }
    }
    

    【讨论】:

      【解决方案4】:

      不错的谜题,不是最优化的,但我的尝试:0/1 用于 int 位,仅递归(和位计数)。结果的数量是(一个 + 零超过一个)。

          int ones = 3;
          int zeroes = 2;
          allIntsWithOnesAndZeroes(ones, zeroes);
      
      public static void allIntsWithOnesAndZeroes(int ones, int zeroes) {
           int bitCount = ones + zeroes;
           int bits = 0;
           SortedSet<Integer> results = new TreeSet<>();
           all(results, bits, 0, bitCount, ones);
      
           System.out.printf("(%d over %d) = %d, #%d: %s%n",
               bitCount, ones, over(bitCount, ones), results.size(), results);
           long a = 0;
           for (int n : results) {
               System.out.println("- " + Integer.toBinaryString(n));
               a |= 1L << n;
           }
           System.out.printf("all: %s%n", Long.toBinaryString(a));
      }
      
      private static void all(Set<Integer> results, int bits, int i, int bitCount, int ones) {
          if (ones == 0) {
              results.add(bits); // Assumes ones > 0.
          }
          if (i >= bitCount) {
              return;
          }
          all(results, bits, i + 1, bitCount, ones);
          int bits2 = bits | (1 << i);
          all(results, bits2, i + 1, bitCount, ones - 1);
      }
      

      一些数学:

      public static long fac(long x) {
          long n = 1;
          while (x > 1) {
              n *= x;
              --x;
          }
          return n;
      }
      
      public static long over(long x, long y) {
          return fac(x) / fac(y) / fac(x - y);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多