查找 X 翻转字符串
考虑例如N=10, X=4 且初始字符串为:
initial: 0011010111
那么这将是一个 X 翻转字符串的示例:
flipped: 0000111111
因为 4 位不同。如果你对这两个字符串进行异或,你会得到:
initial: 0011010111
flipped: 0000111111
XOR-ed: 0011101000
异或字符串中的 4 个设置位(1)表示已翻转的 4 个位的位置。
现在反过来想。如果您有一个初始字符串和一个具有 4 个设置位的字符串,那么您可以通过对它们进行异或运算来生成一个 X 翻转字符串:
initial: 0011010111
4 bits : 0011101000
XOR-ed: 0000111111
因此,如果您生成每个长度为 N 且带有 X 个设置位的二进制字符串,并将它们与初始字符串进行异或,您将得到所有 X 翻转的字符串。
initial 4 bits XOR-ed
0011010111 0000001111 0011011000
0000010111 0011000000
0000100111 0011110000
...
1110010000 1101000111
1110100000 1101110111
1111000000 1100010111
可以生成所有具有 X 组位的 N 长度字符串,例如与Gosper's Hack。在下面的代码示例中,我使用了我最初为this answer 编写的反向字典顺序函数。
双翻转
如果位可以翻转两次,那么X翻转的字符串可能与初始字符串没有X位不同,而只有X-2位,因为一位被翻转,然后又翻转回原来的状态.或 X-4,如果该位被翻转 4 次,或者两个不同的位被翻转两次。事实上,不同位的数量可以是 X、X-2、X-4、X-6 ... 到 1 或 0(取决于 X 是奇数还是偶数)。
因此,要生成所有 X 翻转的字符串,您首先生成所有具有 X 翻转位的字符串,然后生成所有具有 X-2 翻转位的字符串,然后将 X-4、X-6 ... 降至 1 或 0。
如果 X > N
如果 X 大于 N,那么显然有些位会被翻转不止一次。生成它们的方法是相同的:从 X 开始,倒数到 X-2、X-4、X-6 ......但只为值 ≤ N 生成字符串。所以实际上,你从 N 或 N- 开始1,取决于 XN 是偶数还是奇数。
字符串总数
具有 X 个翻转位的 N 长度字符串的数量等于具有 X 个设置位的 N 长度字符串的数量,即Binomial CoefficientN choose X。当然你还得考虑X-2, X-4, X-6 ...翻转位的字符串,所以总数是:
(N 选择 X) + (N 选择 X-2) + (N 选择 X-4) + (N 选择 X-6) + ... + (N 选择 (1 或 0))
在 X 大于 N 的情况下,您从 N choose N 或 N choose N-1 开始,具体取决于 X-N 是偶数还是奇数。
对于 N=3 和 X=2 的示例,总数为:
(3 choose 2) + (3 choose 0) = 3 + 1 = 4
对于上面 N=10 和 X=4 的示例,总数为:
(10 choose 4) + (10 choose 2) + (10 choose 0) = 210 + 45 + 1 = 256
对于另一个答案中 N=6 和 X=4 的示例,正确的数字是:
(6 choose 4) + (6 choose 2) + (6 choose 0) = 15 + 15 + 1 = 31
示例代码
此 JavaScript 代码 sn-p 以相反的字典顺序生成二进制字符串序列(以便设置位从左到右移动),然后打印出结果翻转字符串和上述示例的总数:
function flipBits(init, x) {
var n = init.length, bits = [], count = 0;
if (x > n) x = n - (x - n) % 2; // reduce x if it is greater than n
for (; x >= 0; x -= 2) { // x, x-2, x-4, ... down to 1 or 0
for (var i = 0; i < n; i++) bits[i] = i < x ? 1 : 0; // x ones, then zeros
do {++count;
var flip = XOR(init, bits);
document.write(init + " ⊕ " + bits + " → " + flip + "<br>");
} while (revLexi(bits));
}
return count;
function XOR(a, b) { // XOR's two binary arrays (because JavaScript)
var c = [];
for (var i = 0; i < a.length; i++) c[i] = a[i] ^ b[i];
return c;
}
function revLexi(seq) { // next string in reverse lexicographical order
var max = true, pos = seq.length, set = 1;
while (pos-- && (max || !seq[pos])) if (seq[pos]) ++set; else max = false;
if (pos < 0) return false;
seq[pos] = 0;
while (++pos < seq.length) seq[pos] = set-- > 0 ? 1 : 0;
return true;
}
}
document.write(flipBits([1,1,1], 2) + "<br>");
document.write(flipBits([0,0,1,1,0,1,0,1,1,1], 4) + "<br>");
document.write(flipBits([1,1,1,1,1,1], 4) + "<br>");