生成一个二进制数列表,其中 n 位设置为 1

Posted

技术标签:

【中文标题】生成一个二进制数列表,其中 n 位设置为 1【英文标题】:Generate a list of binary numbers where n bits are set to 1 【发布时间】:2022-01-06 08:29:49 【问题描述】:

我想生成一个包含m 位的二进制数列表,其中n 位设置为1,所有其他位设置为0。例如,假设m 为4。我想生成一个列表具有 4 位的二进制数。 16个数字中,有6个2位为1,其他全为0。

0000
0001
0010
0011 <--
0100
0101 <--
0110 <--
0111
1000
1001 <--
1010 <--
1011
1100 <--
1101
1110
1111

我想为任何m 位生成一个列表,其中n 位设置为1,至少对于n = 2 的情况。但我不确定要遵循什么过程。我当然可以暴力破解它并生成所有m 位的数字,然后单独检查每个数字,但是对于可能需要一段时间的大量位。我觉得必须有一个更巧妙的数学技巧来找出答案。

如果有任何关于从哪里开始的指示,我将不胜感激。我不介意答案是伪代码还是任何语言,只要它们是明确的。


XY 问题

我正在尝试解决国际象棋问题,其中棋盘上有两个棋子。首先,我试图在棋盘上生成两个棋子的所有有效组合,我计划通过将棋盘视为 64 位二进制数 (0000 0000 0000 0000 .. 0011) 来实现,其中一个位是一块。为此,我需要找到一种优雅的方式来生成二进制数列表。


编辑:我尝试在 Python 中实现朴素算法只是为了演示。在我的 VS Code 上执行 m = 64 需要很长时间,所以绝对不是最好的解决方案:

n = 2
m = 64
combos = []
for i in range(2 ** m):
    bin_s = str(format(i, f'0mb'))
    if bin_s.count('1') == n:
        combos.append(bin_s)

for c in combos:
    print(c)

print(f"There are len(combos) combinations")

【问题讨论】:

这有帮助吗?每个具有 n 个 1 的 m 位数要么以 0(后跟带有 n 个 1 的 m-1 位数)或 1(后跟带有 n-1 个 1 的 m-1 位数)开头。 所以对于一个有 2 个 1 的 64 位数字,它要么以 0 开头,然后是 2 个 1 的 63 位数字,或者以 1 后跟 1 1 的 63 位数字开头。诚然,我不确定这如何帮助我提出算法 (大部分)一种算法——一种递归算法。剩下的主要部分是确定答案显而易见的 m 和 n 的情况(例如,如果只有 1 个或更少的数字)。 老实说,我不太擅长从线索中找出答案。您是否建议将二进制中的每个数字从 1 迭代到 2^m(例如 1 到 2^64)并对每个数字应用一些递归算法来确定它是否符合具有两个 1 位的标准?或者使用一些递归算法来生成列表? 你在哪里看到我写的任何东西中的“迭代”这个词?我所描述的是一种生成列表的递归算法,这正是您所要求的。 【参考方案1】:

这在字典上称为下一个排列,在许多位黑客网站中都可用。

https://graphics.stanford.edu/~seander/bithacks.html#NextBitPermutation

x = 0b000000111 开头,例如对于 3 位,一个迭代直到 x &amp; (1 &lt;&lt; m)(或者如果 m == word_size 存在溢出)。

uint64_t next(uint64_t v) 
    uint64_t t = v | (v - 1); // t gets v's least significant 0 bits set to 1
    // Next set to 1 the most significant bit to change, 
    // set to 0 the least significant ones, and add the necessary 1 bits.
    return (t + 1) | (((~t & -~t) - 1) >> (__builtin_ctz(v) + 1));  


uint64_t v = 15; // 4 bits
do 
   my_func(v);
   if (v == 0xf000000000000000ull) 
       break;
   
   v = next(v);
 while (true);

【讨论】:

【参考方案2】:

使用https://docs.python.org/3/library/itertools.html#itertools.combinations 生成您拥有 1 的索引集。将其转换为二进制数很简单。

如果你想用另一种语言来解决这个问题,文档有本地 Python 代码来解决这个问题。

【讨论】:

以上是关于生成一个二进制数列表,其中 n 位设置为 1的主要内容,如果未能解决你的问题,请参考以下文章

如何在未知大小的二进制数中将所有位设置为“1”?

8.位运算

剑指offer11:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。(进制转换,补码反码)

MFC 如何生成一个32位字节的16进制数

将大小为 n 的二进制数生成为元组:itertools.product(*[(0, 1)] * n)

剑指offer 二进制中1的个数