我试图解决一个更大的问题。作为其中的一部分,我创建了一个BitArray来表示顺序执行的一系列二进制决策。我知道所有有效的决策系列都会有一半的决定是真的,有一半是假的,但我不知道顺序:
ttttffff
[||||||||]
或者:
tftftftf
[||||||||]
或者:
ttffttff
[||||||||]
或任何其他组合,其中一半的所有位都为真,一半是假的。
我的BitArray比这长得多,我需要遍历每组可能的决定(每个可能的半真半假的组合),进一步检查它们的有效性。然而,我在概念上努力解决如何使用循环来解决这个问题。看起来它应该很简单,但我的大脑让我失望。
编辑:因为BitArray不是很大,我使用了usr的建议并实现了一个bithift循环。根据一些评论和答案,我用关键词"排列"重新搜索了问题。并发现this Stack Overflow问题非常相似。
答案 0 :(得分:2)
我使用递归算法来做到这一点。每个级别设置下一个位。您可以跟踪已经确定了多少个零和一个零。如果其中一个计数器高于N / 2
,则中止分支并回溯。这应该提供相当好的性能,因为它会倾向于快速切断不可行的分支。例如,设置tttt
后,只有f
个选项可行。
更简单,性能较差的版本是使用for循环遍历所有可能的N位整数并丢弃不满足条件的那些整数。这很容易实现高达63位。只需从0
到1 << 63
进行for循环。显然,对于高位,这太慢了。
您正在寻找N / 2
零和N / 2
个的所有排列。有生成这些的算法。如果你能找到一个实现的,那么应该给出最好的性能。我相信这些算法使用聪明的数学技巧来访问可行的组合。
答案 1 :(得分:2)
如果你可以使用整数中的位而不是BitArray,这是生成所有模式的通用解决方案,并设置了一些常数位。
从最低有效值开始,该值与数字右侧的所有值有关,您可以将其计算为low = ~(-1 << k)
(对于k = 32不起作用,但这不是问题这种情况)。
然后取Gosper's Hack(也在this回答中显示),这是一种生成下一个最高整数且设置相同位数的方法,并继续应用它直到达到最高有效值,在这种情况下low << k
。
答案 2 :(得分:1)
这将导致重复,但如果您愿意,可以在添加到列表之前检查重复项。
static void Main(string[] args)
{
// Set your bits here:
bool[] bits = { true, true, false };
BitArray original_bits = new BitArray(bits);
permuteBits(original_bits, 0, original_bits.Length - 1);
foreach (BitArray ba in permutations)
{
// You can check Validity Here
foreach (bool i in ba)
{
Console.Write(Convert.ToInt32(i));
}
Console.WriteLine();
}
}
static List<BitArray> permutations = new List<BitArray>();
static void permuteBits(BitArray bits, int minIndex, int maxIndex)
{
int current_index;
if (minIndex == maxIndex)
{
permutations.Add(new BitArray(bits));
}
else
{
for (current_index = minIndex; current_index <= maxIndex; current_index++)
{
swap(bits, minIndex, current_index);
permuteBits(bits, minIndex + 1, maxIndex);
swap(bits, minIndex, current_index);
}
}
}
private static void swap(BitArray bits, int i, int j)
{
bool temp = bits[i];
bits[i] = bits[j];
bits[j] = temp;
}
答案 3 :(得分:0)
如果您想清除具有重复条目的字符串finding all the permutation
的概念(即zeros and ones
),您可以阅读此article
他们使用递归解决方案来解决这个问题,解释也很好。