如何快速列出63位二进制中有36个1和27个0的所有二进制组合
问题描述:
000000000000000000000000000000000000000000000000000000000000000
111111111111111111111111111111111111111111111111111111111111111
以上是63位2进制,用哪种方法可以不用遍历列出所有的36个1和27个0的所有二进制组合
例如:
第一组
000000000000000000000000000111111111111111111111111111111111111
第二组....第三组....
求大神帮忙。。。
答
这是个简单的排列组合,只是你的数据太大,很可能内存扛不住,下面有两种简单的方式处理这种问题 (Java 实现)。
1、暴力迭代搜索
public static List<String> solution0(int zeroNumber, int oneNumber) { if ((zeroNumber | oneNumber) < 0) { throw new IllegalArgumentException(String.format("The number of zero or one is negative : zero = %s, one = %s.", zeroNumber, oneNumber)); } int sequenceLen = zeroNumber + oneNumber; if (sequenceLen == zeroNumber || sequenceLen == oneNumber) { String sequence = new String(IntStream.range(0, sequenceLen).map(i -> zeroNumber == 0 ? '1' : '0').toArray(), 0, sequenceLen); return Collections.singletonList(sequence); } /* C(m, m + n),计算总数,提前初始化,避免扩容,不过可能出现溢出的情况。 */ List<String> sequences = new ArrayList<>(); char[] values = new char[sequenceLen]; Arrays.fill(values, '0'); helper(0, oneNumber, values, 0, sequences); return sequences; } private static void helper(int oneCount, int oneNumber, char[] values, int pos, List<String> sequences) { if (oneNumber - oneCount > values.length - pos) { return; } if (oneCount == oneNumber) { sequences.add(new String(values)); return; } values[pos] = '1'; helper(oneCount + 1, oneNumber, values, pos + 1, sequences); values[pos] = '0'; helper(oneCount, oneNumber, values, pos + 1, sequences); }
2、针对零和一的数量和小于等于 64 的优化版本
public static String[] solution1(int zeroNumber, int oneNumber) { final int sequenceLen = zeroNumber + oneNumber; if ((zeroNumber | oneNumber) < 0 || sequenceLen > 64) { throw new IllegalArgumentException(String.format("The number of zero or one are abnormal : zero = %s, one = %s.", zeroNumber, oneNumber)); } if (sequenceLen == zeroNumber || sequenceLen == oneNumber) { String sequence = new String(IntStream.range(0, sequenceLen).map(i -> zeroNumber == 0 ? '1' : '0').toArray(), 0, sequenceLen); return new String[]{sequence}; } final int resultNumber = (int) MathUtils.nchoosek(sequenceLen, oneNumber); long[][] binaryValues = new long[resultNumber][2]; /* 索引 0 记录二进制值,索引 1 记录 1 的数量 */ binaryValues[0] = new long[]{0, 0}; binaryValues[1] = new long[]{1, 1}; for (int i = 1, count = 2; i < sequenceLen; ++i) { int index = count; for (int j = 0; j < count; ++j) { long value = binaryValues[j][0]; long oneCount = binaryValues[j][1]; if (oneCount == oneNumber) { continue; } if (oneNumber - oneCount == sequenceLen - i) { binaryValues[j][0] = value | (1L << i); binaryValues[j][1] = oneCount + 1; continue; } binaryValues[index++] = new long[]{value | (1L << i), oneCount + 1}; } count = index; } String[] result = new String[resultNumber]; for (int i = 0; i < resultNumber; ++i) { /* 简单转换 long 数值为二进制字符串 */ char[] chars = new char[(int) sequenceLen]; for (int j = 0; j < sequenceLen; ++j) { chars[j] = (char) (((binaryValues[i][0] >>> j) & 1) + '0'); } result[i] = new String(chars); binaryValues[i] = null; } return result; }