如何迭代平衡的二进制字符串?

How can I iterate over balanced binary strings?

提问人:tparker 提问时间:2/15/2018 更新时间:2/15/2018 访问量:297

问:

我需要系统地遍历(偶数)长度为 n 的平衡二进制字符串集,即由相等数量的 1 和 0 组成的二进制字符串。 (这个问题可以用许多等效的方式表示;例如,给定集合 S = {1, 2, ..., n},如何遍历 S 的平衡二分法,或大小为 n/2 的 S 子集。最有效的方法是什么?

最幼稚的算法是简单地遍历所有二进制字符串(例如,按照标准词典顺序),然后跳过所有不平衡的字符串。但这是非常低效的:有 2^n 个长度为 n 的二进制字符串,但只有 (n 选择 n/2) 是平衡的。根据斯特林的近似,这个量渐近增长为 $\sqrt{2/(\pi n)} 2^n$,因此只有一小部分 ~1/n 的二进制字符串是平衡的。

在我看来,更有效的实现可能是这样的:你从字符串 000...0111...1 开始,然后通过一系列相邻的转置 01 -> 10 将 1 跳到左边。但是我无法想出一种方法来组织转置,以便每个平衡的二进制字符串都产生一次。例如,如果你总是转置最左边的 01,那么你会错过很多字符串(例如 0110),但如果在每一步你都把每个可能的转调分支到一个树中,那么你会多计算很多字符串(例如 0101 -> 1010 可以通过按任一顺序执行两个转换来达到)。

(如果算法易于推广,能够迭代具有任意固定不平衡的 n 位二进制字符串集,那就太好了,但不是必需的。

字符串 算法 与语言无关 的迭代

评论

0赞 phoxis 2/15/2018
您能否澄清一下“S 的平衡二分法或大小为 n/2 的 S 子集”的确切含义。?
0赞 tparker 2/15/2018
@phoxis 我所说的“S 的平衡二分法”是指将集合 {1, 2, ..., n} 分成两个子集,每个子集包含相等数量的 n/2 个元素。这种二分法可以通过仅指定两个子集 T(大小为 n/2)中的一个来等效地指定,因为另一个子集随后被唯一确定为集合补码 S \ T。
2赞 cadaniluk 2/15/2018
这篇MSDN帖子似乎就是你所追求的。

答:

1赞 גלעד ברקן 2/15/2018 #1

下面是一个 Python 递归(可以很容易地转换为堆栈迭代;内部函数中提供了任意固定的不平衡):g

def f(n):
  def g(n, k, s):
    if len(s) == n:
      return [s]

    if len(s) + k == n:
      return [s + (n - len(s)) * '1']

    if k == 0:
      return [s + (n - len(s)) * '0']

    return g(n, k, s + '0') + g(n, k - 1, s + '1')

  return g(n, n / 2, '')

输出:

=> f(6)
=> ['000111', '001011', '001101', '001110', '010011', '010101', '010110', '011001', '011010', '011100', '100011', '100101', '100110', '101001', '101010', '101100', '110001', '110010', '110100', '111000']